get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 103055,
    "url": "http://patches.dpdk.org/api/patches/103055/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20211027142213.556166-2-maxime.coquelin@redhat.com/",
    "project": {
        "id": 1,
        "url": "http://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": "<20211027142213.556166-2-maxime.coquelin@redhat.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20211027142213.556166-2-maxime.coquelin@redhat.com",
    "date": "2021-10-27T14:22:09",
    "name": "[v6,1/5] net/virtio: add initial RSS support",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "16fcf2f6a1781043b5b6c12ce9e2592d0ce31ade",
    "submitter": {
        "id": 512,
        "url": "http://patches.dpdk.org/api/people/512/?format=api",
        "name": "Maxime Coquelin",
        "email": "maxime.coquelin@redhat.com"
    },
    "delegate": {
        "id": 2642,
        "url": "http://patches.dpdk.org/api/users/2642/?format=api",
        "username": "mcoquelin",
        "first_name": "Maxime",
        "last_name": "Coquelin",
        "email": "maxime.coquelin@redhat.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20211027142213.556166-2-maxime.coquelin@redhat.com/mbox/",
    "series": [
        {
            "id": 20057,
            "url": "http://patches.dpdk.org/api/series/20057/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=20057",
            "date": "2021-10-27T14:22:08",
            "name": "Virtio PMD RSS support & RSS fixes",
            "version": 6,
            "mbox": "http://patches.dpdk.org/series/20057/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/103055/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/103055/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 DE012A0C47;\n\tWed, 27 Oct 2021 16:23:42 +0200 (CEST)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id CB21441161;\n\tWed, 27 Oct 2021 16:23:42 +0200 (CEST)",
            "from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.133.124])\n by mails.dpdk.org (Postfix) with ESMTP id 6739C40DDA\n for <dev@dpdk.org>; Wed, 27 Oct 2021 16:23:41 +0200 (CEST)",
            "from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com\n [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id\n us-mta-482-yiO9-Zg3OmWkCeXTKSJVLQ-1; Wed, 27 Oct 2021 10:23:33 -0400",
            "from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com\n [10.5.11.22])\n (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))\n (No client certificate requested)\n by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 89FA41808324;\n Wed, 27 Oct 2021 14:23:31 +0000 (UTC)",
            "from max-t490s.redhat.com (unknown [10.39.208.21])\n by smtp.corp.redhat.com (Postfix) with ESMTP id E442A10016FE;\n Wed, 27 Oct 2021 14:23:02 +0000 (UTC)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1635344620;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:content-type:content-type:\n content-transfer-encoding:content-transfer-encoding:\n in-reply-to:in-reply-to:references:references;\n bh=GfE95xbjJbFz03eKGsvYqpmKLnvZxWzbY1nOEtavzfI=;\n b=iuicCyhhTZgb22WAvxqHl/G8vXhDdBNgKF9lZLweXLniwqxw2ISl+gkkn7+lpWr0u+6VdG\n FhuOLWd24mrDFUfQJZ/ltFrQIn7WZ2BDWSQ9nvMYhrQ+fsQ1EHGfUQSeGjoXTu1gK1VBbq\n U+SukPmwrextyGKErIj9NiUcH8JnYbw=",
        "X-MC-Unique": "yiO9-Zg3OmWkCeXTKSJVLQ-1",
        "From": "Maxime Coquelin <maxime.coquelin@redhat.com>",
        "To": "dev@dpdk.org, chenbo.xia@intel.com, amorenoz@redhat.com,\n david.marchand@redhat.com, andrew.rybchenko@oktetlabs.ru,\n ferruh.yigit@intel.com, michaelba@nvidia.com, viacheslavo@nvidia.com,\n xiaoyun.li@intel.com",
        "Cc": "nelio.laranjeiro@6wind.com, yvugenfi@redhat.com, ybendito@redhat.com,\n Maxime Coquelin <maxime.coquelin@redhat.com>",
        "Date": "Wed, 27 Oct 2021 16:22:09 +0200",
        "Message-Id": "<20211027142213.556166-2-maxime.coquelin@redhat.com>",
        "In-Reply-To": "<20211027142213.556166-1-maxime.coquelin@redhat.com>",
        "References": "<20211027142213.556166-1-maxime.coquelin@redhat.com>",
        "MIME-Version": "1.0",
        "X-Scanned-By": "MIMEDefang 2.84 on 10.5.11.22",
        "Authentication-Results": "relay.mimecast.com;\n auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=maxime.coquelin@redhat.com",
        "X-Mimecast-Spam-Score": "0",
        "X-Mimecast-Originator": "redhat.com",
        "Content-Transfer-Encoding": "8bit",
        "Content-Type": "text/plain; charset=\"US-ASCII\"",
        "Subject": "[dpdk-dev] [PATCH v6 1/5] net/virtio: add initial RSS support",
        "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": "Provide the capability to update the hash key, hash types\nand RETA table on the fly (without needing to stop/start\nthe device). However, the key length and the number of RETA\nentries are fixed to 40B and 128 entries respectively. This\nis done in order to simplify the design, but may be\nrevisited later as the Virtio spec provides this\nflexibility.\n\nNote that only VIRTIO_NET_F_RSS support is implemented,\nVIRTIO_NET_F_HASH_REPORT, which would enable reporting the\npacket RSS hash calculated by the device into mbuf.rss, is\nnot yet supported.\n\nRegarding the default RSS configuration, it has been\nchosen to use the default Intel ixgbe key as default key,\nand default RETA is a simple modulo between the hash and\nthe number of Rx queues.\n\nSigned-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>\n---\n doc/guides/nics/features/virtio.ini    |   3 +\n doc/guides/nics/virtio.rst             |   3 +\n doc/guides/rel_notes/release_21_11.rst |   6 +\n drivers/net/virtio/virtio.h            |  32 +-\n drivers/net/virtio/virtio_ethdev.c     | 436 ++++++++++++++++++++++++-\n drivers/net/virtio/virtio_ethdev.h     |   3 +-\n drivers/net/virtio/virtqueue.h         |  25 ++\n 7 files changed, 499 insertions(+), 9 deletions(-)",
    "diff": "diff --git a/doc/guides/nics/features/virtio.ini b/doc/guides/nics/features/virtio.ini\nindex 48f6f393b1..a5eab4932f 100644\n--- a/doc/guides/nics/features/virtio.ini\n+++ b/doc/guides/nics/features/virtio.ini\n@@ -14,6 +14,9 @@ Promiscuous mode     = Y\n Allmulticast mode    = Y\n Unicast MAC filter   = Y\n Multicast MAC filter = Y\n+RSS hash             = P\n+RSS key update       = Y\n+RSS reta update      = Y\n VLAN filter          = Y\n Basic stats          = Y\n Stats per queue      = Y\ndiff --git a/doc/guides/nics/virtio.rst b/doc/guides/nics/virtio.rst\nindex 82ce7399ce..98e0d012b7 100644\n--- a/doc/guides/nics/virtio.rst\n+++ b/doc/guides/nics/virtio.rst\n@@ -73,6 +73,9 @@ In this release, the virtio PMD driver provides the basic functionality of packe\n \n *   Virtio supports using port IO to get PCI resource when UIO module is not available.\n \n+*   Virtio supports RSS Rx mode with 40B configurable hash key length, 128\n+    configurable RETA entries and configurable hash types.\n+\n Prerequisites\n -------------\n \ndiff --git a/doc/guides/rel_notes/release_21_11.rst b/doc/guides/rel_notes/release_21_11.rst\nindex 1ccac87b73..bfdd0fe0e2 100644\n--- a/doc/guides/rel_notes/release_21_11.rst\n+++ b/doc/guides/rel_notes/release_21_11.rst\n@@ -305,6 +305,12 @@ New Features\n     * Pcapng format with timestamps and meta-data.\n     * Fixes packet capture with stripped VLAN tags.\n \n+* **Added initial RSS support to Virtio PMD.**\n+\n+  Initial support for RSS receive mode has been added to the Virtio PMD,\n+  with the capability for the application to configure the hash key, the\n+  RETA and the hash types. Virtio hash reporting is yet to be added.\n+\n \n Removed Items\n -------------\ndiff --git a/drivers/net/virtio/virtio.h b/drivers/net/virtio/virtio.h\nindex e78b2e429e..9a2ab2caea 100644\n--- a/drivers/net/virtio/virtio.h\n+++ b/drivers/net/virtio/virtio.h\n@@ -30,6 +30,7 @@\n #define VIRTIO_NET_F_GUEST_ANNOUNCE 21\t/* Guest can announce device on the network */\n #define VIRTIO_NET_F_MQ\t\t22\t/* Device supports Receive Flow Steering */\n #define VIRTIO_NET_F_CTRL_MAC_ADDR 23\t/* Set MAC address */\n+#define VIRTIO_NET_F_RSS\t60\t/* RSS supported */\n \n /*\n  * Do we get callbacks when the ring is completely used,\n@@ -100,6 +101,29 @@\n  */\n #define VIRTIO_MAX_INDIRECT ((int)(rte_mem_page_size() / 16))\n \n+/*  Virtio RSS hash types */\n+#define VIRTIO_NET_HASH_TYPE_IPV4\tRTE_BIT32(0)\n+#define VIRTIO_NET_HASH_TYPE_TCPV4\tRTE_BIT32(1)\n+#define VIRTIO_NET_HASH_TYPE_UDPV4\tRTE_BIT32(2)\n+#define VIRTIO_NET_HASH_TYPE_IPV6\tRTE_BIT32(3)\n+#define VIRTIO_NET_HASH_TYPE_TCPV6\tRTE_BIT32(4)\n+#define VIRTIO_NET_HASH_TYPE_UDPV6\tRTE_BIT32(5)\n+#define VIRTIO_NET_HASH_TYPE_IP_EX\tRTE_BIT32(6)\n+#define VIRTIO_NET_HASH_TYPE_TCP_EX\tRTE_BIT32(7)\n+#define VIRTIO_NET_HASH_TYPE_UDP_EX\tRTE_BIT32(8)\n+\n+#define VIRTIO_NET_HASH_TYPE_MASK ( \\\n+\tVIRTIO_NET_HASH_TYPE_IPV4 | \\\n+\tVIRTIO_NET_HASH_TYPE_TCPV4 | \\\n+\tVIRTIO_NET_HASH_TYPE_UDPV4 | \\\n+\tVIRTIO_NET_HASH_TYPE_IPV6 | \\\n+\tVIRTIO_NET_HASH_TYPE_TCPV6 | \\\n+\tVIRTIO_NET_HASH_TYPE_UDPV6 | \\\n+\tVIRTIO_NET_HASH_TYPE_IP_EX | \\\n+\tVIRTIO_NET_HASH_TYPE_TCP_EX | \\\n+\tVIRTIO_NET_HASH_TYPE_UDP_EX)\n+\n+\n /*\n  * Maximum number of virtqueues per device.\n  */\n@@ -157,7 +181,9 @@ struct virtio_net_config {\n \t * Any other value stands for unknown.\n \t */\n \tuint8_t duplex;\n-\n+\tuint8_t rss_max_key_size;\n+\tuint16_t rss_max_indirection_table_length;\n+\tuint32_t supported_hash_types;\n } __rte_packed;\n \n struct virtio_hw {\n@@ -190,6 +216,10 @@ struct virtio_hw {\n \trte_spinlock_t state_lock;\n \tstruct rte_mbuf **inject_pkts;\n \tuint16_t max_queue_pairs;\n+\tuint16_t rss_rx_queues;\n+\tuint32_t rss_hash_types;\n+\tuint16_t *rss_reta;\n+\tuint8_t *rss_key;\n \tuint64_t req_guest_features;\n \tstruct virtnet_ctl *cvq;\n \tbool use_va;\ndiff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c\nindex 26de006c77..08e4c28946 100644\n--- a/drivers/net/virtio/virtio_ethdev.c\n+++ b/drivers/net/virtio/virtio_ethdev.c\n@@ -51,6 +51,16 @@ static int virtio_dev_info_get(struct rte_eth_dev *dev,\n static int virtio_dev_link_update(struct rte_eth_dev *dev,\n \tint wait_to_complete);\n static int virtio_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask);\n+static int virtio_dev_rss_hash_update(struct rte_eth_dev *dev,\n+\t\tstruct rte_eth_rss_conf *rss_conf);\n+static int virtio_dev_rss_hash_conf_get(struct rte_eth_dev *dev,\n+\t\tstruct rte_eth_rss_conf *rss_conf);\n+static int virtio_dev_rss_reta_update(struct rte_eth_dev *dev,\n+\t\t\t struct rte_eth_rss_reta_entry64 *reta_conf,\n+\t\t\t uint16_t reta_size);\n+static int virtio_dev_rss_reta_query(struct rte_eth_dev *dev,\n+\t\t\t struct rte_eth_rss_reta_entry64 *reta_conf,\n+\t\t\t uint16_t reta_size);\n \n static void virtio_set_hwaddr(struct virtio_hw *hw);\n static void virtio_get_hwaddr(struct virtio_hw *hw);\n@@ -347,20 +357,52 @@ virtio_send_command(struct virtnet_ctl *cvq, struct virtio_pmd_ctrl *ctrl,\n }\n \n static int\n-virtio_set_multiple_queues(struct rte_eth_dev *dev, uint16_t nb_queues)\n+virtio_set_multiple_queues_rss(struct rte_eth_dev *dev, uint16_t nb_queues)\n {\n \tstruct virtio_hw *hw = dev->data->dev_private;\n \tstruct virtio_pmd_ctrl ctrl;\n-\tint dlen[1];\n+\tstruct virtio_net_ctrl_rss rss;\n+\tint dlen, ret;\n+\n+\trss.hash_types = hw->rss_hash_types & VIRTIO_NET_HASH_TYPE_MASK;\n+\tRTE_BUILD_BUG_ON(!RTE_IS_POWER_OF_2(VIRTIO_NET_RSS_RETA_SIZE));\n+\trss.indirection_table_mask = VIRTIO_NET_RSS_RETA_SIZE - 1;\n+\trss.unclassified_queue = 0;\n+\tmemcpy(rss.indirection_table, hw->rss_reta, VIRTIO_NET_RSS_RETA_SIZE * sizeof(uint16_t));\n+\trss.max_tx_vq = nb_queues;\n+\trss.hash_key_length = VIRTIO_NET_RSS_KEY_SIZE;\n+\tmemcpy(rss.hash_key_data, hw->rss_key, VIRTIO_NET_RSS_KEY_SIZE);\n+\n+\tctrl.hdr.class = VIRTIO_NET_CTRL_MQ;\n+\tctrl.hdr.cmd = VIRTIO_NET_CTRL_MQ_RSS_CONFIG;\n+\tmemcpy(ctrl.data, &rss, sizeof(rss));\n+\n+\tdlen = sizeof(rss);\n+\n+\tret = virtio_send_command(hw->cvq, &ctrl, &dlen, 1);\n+\tif (ret) {\n+\t\tPMD_INIT_LOG(ERR, \"RSS multiqueue configured but send command failed\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+virtio_set_multiple_queues_auto(struct rte_eth_dev *dev, uint16_t nb_queues)\n+{\n+\tstruct virtio_hw *hw = dev->data->dev_private;\n+\tstruct virtio_pmd_ctrl ctrl;\n+\tint dlen;\n \tint ret;\n \n \tctrl.hdr.class = VIRTIO_NET_CTRL_MQ;\n \tctrl.hdr.cmd = VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET;\n \tmemcpy(ctrl.data, &nb_queues, sizeof(uint16_t));\n \n-\tdlen[0] = sizeof(uint16_t);\n+\tdlen = sizeof(uint16_t);\n \n-\tret = virtio_send_command(hw->cvq, &ctrl, dlen, 1);\n+\tret = virtio_send_command(hw->cvq, &ctrl, &dlen, 1);\n \tif (ret) {\n \t\tPMD_INIT_LOG(ERR, \"Multiqueue configured but send command \"\n \t\t\t  \"failed, this is too late now...\");\n@@ -370,6 +412,17 @@ virtio_set_multiple_queues(struct rte_eth_dev *dev, uint16_t nb_queues)\n \treturn 0;\n }\n \n+static int\n+virtio_set_multiple_queues(struct rte_eth_dev *dev, uint16_t nb_queues)\n+{\n+\tstruct virtio_hw *hw = dev->data->dev_private;\n+\n+\tif (virtio_with_feature(hw, VIRTIO_NET_F_RSS))\n+\t\treturn virtio_set_multiple_queues_rss(dev, nb_queues);\n+\telse\n+\t\treturn virtio_set_multiple_queues_auto(dev, nb_queues);\n+}\n+\n static uint16_t\n virtio_get_nr_vq(struct virtio_hw *hw)\n {\n@@ -708,6 +761,16 @@ virtio_alloc_queues(struct rte_eth_dev *dev)\n \n static void virtio_queues_unbind_intr(struct rte_eth_dev *dev);\n \n+static void\n+virtio_free_rss(struct virtio_hw *hw)\n+{\n+\trte_free(hw->rss_key);\n+\thw->rss_key = NULL;\n+\n+\trte_free(hw->rss_reta);\n+\thw->rss_reta = NULL;\n+}\n+\n int\n virtio_dev_close(struct rte_eth_dev *dev)\n {\n@@ -737,6 +800,7 @@ virtio_dev_close(struct rte_eth_dev *dev)\n \tvirtio_reset(hw);\n \tvirtio_dev_free_mbufs(dev);\n \tvirtio_free_queues(hw);\n+\tvirtio_free_rss(hw);\n \n \treturn VIRTIO_OPS(hw)->dev_close(hw);\n }\n@@ -977,6 +1041,10 @@ static const struct eth_dev_ops virtio_eth_dev_ops = {\n \t.rx_queue_intr_enable    = virtio_dev_rx_queue_intr_enable,\n \t.rx_queue_intr_disable   = virtio_dev_rx_queue_intr_disable,\n \t.tx_queue_setup          = virtio_dev_tx_queue_setup,\n+\t.rss_hash_update         = virtio_dev_rss_hash_update,\n+\t.rss_hash_conf_get       = virtio_dev_rss_hash_conf_get,\n+\t.reta_update             = virtio_dev_rss_reta_update,\n+\t.reta_query              = virtio_dev_rss_reta_query,\n \t/* collect stats per queue */\n \t.queue_stats_mapping_set = virtio_dev_queue_stats_mapping_set,\n \t.vlan_filter_set         = virtio_vlan_filter_set,\n@@ -1718,6 +1786,332 @@ virtio_configure_intr(struct rte_eth_dev *dev)\n \n \treturn 0;\n }\n+\n+static uint64_t\n+ethdev_to_virtio_rss_offloads(uint64_t ethdev_hash_types)\n+{\n+\tuint64_t virtio_hash_types = 0;\n+\n+\tif (ethdev_hash_types & (ETH_RSS_IPV4 | ETH_RSS_FRAG_IPV4 | ETH_RSS_NONFRAG_IPV4_OTHER))\n+\t\tvirtio_hash_types |= VIRTIO_NET_HASH_TYPE_IPV4;\n+\n+\tif (ethdev_hash_types & ETH_RSS_NONFRAG_IPV4_TCP)\n+\t\tvirtio_hash_types |= VIRTIO_NET_HASH_TYPE_TCPV4;\n+\n+\tif (ethdev_hash_types & ETH_RSS_NONFRAG_IPV4_UDP)\n+\t\tvirtio_hash_types |= VIRTIO_NET_HASH_TYPE_UDPV4;\n+\n+\tif (ethdev_hash_types & (ETH_RSS_IPV6 | ETH_RSS_FRAG_IPV6 | ETH_RSS_NONFRAG_IPV6_OTHER))\n+\t\tvirtio_hash_types |= VIRTIO_NET_HASH_TYPE_IPV6;\n+\n+\tif (ethdev_hash_types & ETH_RSS_NONFRAG_IPV6_TCP)\n+\t\tvirtio_hash_types |= VIRTIO_NET_HASH_TYPE_TCPV6;\n+\n+\tif (ethdev_hash_types & ETH_RSS_NONFRAG_IPV6_UDP)\n+\t\tvirtio_hash_types |= VIRTIO_NET_HASH_TYPE_UDPV6;\n+\n+\tif (ethdev_hash_types & ETH_RSS_IPV6_EX)\n+\t\tvirtio_hash_types |= VIRTIO_NET_HASH_TYPE_IP_EX;\n+\n+\tif (ethdev_hash_types & ETH_RSS_IPV6_TCP_EX)\n+\t\tvirtio_hash_types |= VIRTIO_NET_HASH_TYPE_TCP_EX;\n+\n+\tif (ethdev_hash_types & ETH_RSS_IPV6_UDP_EX)\n+\t\tvirtio_hash_types |= VIRTIO_NET_HASH_TYPE_UDP_EX;\n+\n+\treturn virtio_hash_types;\n+}\n+\n+static uint64_t\n+virtio_to_ethdev_rss_offloads(uint64_t virtio_hash_types)\n+{\n+\tuint64_t rss_offloads = 0;\n+\n+\tif (virtio_hash_types & VIRTIO_NET_HASH_TYPE_IPV4)\n+\t\trss_offloads |= ETH_RSS_IPV4 | ETH_RSS_FRAG_IPV4 | ETH_RSS_NONFRAG_IPV4_OTHER;\n+\n+\tif (virtio_hash_types & VIRTIO_NET_HASH_TYPE_TCPV4)\n+\t\trss_offloads |= ETH_RSS_NONFRAG_IPV4_TCP;\n+\n+\tif (virtio_hash_types & VIRTIO_NET_HASH_TYPE_UDPV4)\n+\t\trss_offloads |= ETH_RSS_NONFRAG_IPV4_UDP;\n+\n+\tif (virtio_hash_types & VIRTIO_NET_HASH_TYPE_IPV6)\n+\t\trss_offloads |= ETH_RSS_IPV6 | ETH_RSS_FRAG_IPV6 | ETH_RSS_NONFRAG_IPV6_OTHER;\n+\n+\tif (virtio_hash_types & VIRTIO_NET_HASH_TYPE_TCPV6)\n+\t\trss_offloads |= ETH_RSS_NONFRAG_IPV6_TCP;\n+\n+\tif (virtio_hash_types & VIRTIO_NET_HASH_TYPE_UDPV6)\n+\t\trss_offloads |= ETH_RSS_NONFRAG_IPV6_UDP;\n+\n+\tif (virtio_hash_types & VIRTIO_NET_HASH_TYPE_IP_EX)\n+\t\trss_offloads |= ETH_RSS_IPV6_EX;\n+\n+\tif (virtio_hash_types & VIRTIO_NET_HASH_TYPE_TCP_EX)\n+\t\trss_offloads |= ETH_RSS_IPV6_TCP_EX;\n+\n+\tif (virtio_hash_types & VIRTIO_NET_HASH_TYPE_UDP_EX)\n+\t\trss_offloads |= ETH_RSS_IPV6_UDP_EX;\n+\n+\treturn rss_offloads;\n+}\n+\n+static int\n+virtio_dev_get_rss_config(struct virtio_hw *hw, uint32_t *rss_hash_types)\n+{\n+\tstruct virtio_net_config local_config;\n+\tstruct virtio_net_config *config = &local_config;\n+\n+\tvirtio_read_dev_config(hw,\n+\t\t\toffsetof(struct virtio_net_config, rss_max_key_size),\n+\t\t\t&config->rss_max_key_size,\n+\t\t\tsizeof(config->rss_max_key_size));\n+\tif (config->rss_max_key_size < VIRTIO_NET_RSS_KEY_SIZE) {\n+\t\tPMD_INIT_LOG(ERR, \"Invalid device RSS max key size (%u)\",\n+\t\t\t\tconfig->rss_max_key_size);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tvirtio_read_dev_config(hw,\n+\t\t\toffsetof(struct virtio_net_config,\n+\t\t\t\trss_max_indirection_table_length),\n+\t\t\t&config->rss_max_indirection_table_length,\n+\t\t\tsizeof(config->rss_max_indirection_table_length));\n+\tif (config->rss_max_indirection_table_length < VIRTIO_NET_RSS_RETA_SIZE) {\n+\t\tPMD_INIT_LOG(ERR, \"Invalid device RSS max reta size (%u)\",\n+\t\t\t\tconfig->rss_max_indirection_table_length);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tvirtio_read_dev_config(hw,\n+\t\t\toffsetof(struct virtio_net_config, supported_hash_types),\n+\t\t\t&config->supported_hash_types,\n+\t\t\tsizeof(config->supported_hash_types));\n+\tif ((config->supported_hash_types & VIRTIO_NET_HASH_TYPE_MASK) == 0) {\n+\t\tPMD_INIT_LOG(ERR, \"Invalid device RSS hash types (0x%x)\",\n+\t\t\t\tconfig->supported_hash_types);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t*rss_hash_types = config->supported_hash_types & VIRTIO_NET_HASH_TYPE_MASK;\n+\n+\tPMD_INIT_LOG(DEBUG, \"Device RSS config:\");\n+\tPMD_INIT_LOG(DEBUG, \"\\t-Max key size: %u\", config->rss_max_key_size);\n+\tPMD_INIT_LOG(DEBUG, \"\\t-Max reta size: %u\", config->rss_max_indirection_table_length);\n+\tPMD_INIT_LOG(DEBUG, \"\\t-Supported hash types: 0x%x\", *rss_hash_types);\n+\n+\treturn 0;\n+}\n+\n+static int\n+virtio_dev_rss_hash_update(struct rte_eth_dev *dev,\n+\t\tstruct rte_eth_rss_conf *rss_conf)\n+{\n+\tstruct virtio_hw *hw = dev->data->dev_private;\n+\tchar old_rss_key[VIRTIO_NET_RSS_KEY_SIZE];\n+\tuint32_t old_hash_types;\n+\tuint16_t nb_queues;\n+\tint ret;\n+\n+\tif (!virtio_with_feature(hw, VIRTIO_NET_F_RSS))\n+\t\treturn -ENOTSUP;\n+\n+\tif (rss_conf->rss_hf & ~virtio_to_ethdev_rss_offloads(VIRTIO_NET_HASH_TYPE_MASK))\n+\t\treturn -EINVAL;\n+\n+\told_hash_types = hw->rss_hash_types;\n+\thw->rss_hash_types = ethdev_to_virtio_rss_offloads(rss_conf->rss_hf);\n+\n+\tif (rss_conf->rss_key && rss_conf->rss_key_len) {\n+\t\tif (rss_conf->rss_key_len != VIRTIO_NET_RSS_KEY_SIZE) {\n+\t\t\tPMD_INIT_LOG(ERR, \"Driver only supports %u RSS key length\",\n+\t\t\t\t\tVIRTIO_NET_RSS_KEY_SIZE);\n+\t\t\tret = -EINVAL;\n+\t\t\tgoto restore_types;\n+\t\t}\n+\t\tmemcpy(old_rss_key, hw->rss_key, VIRTIO_NET_RSS_KEY_SIZE);\n+\t\tmemcpy(hw->rss_key, rss_conf->rss_key, VIRTIO_NET_RSS_KEY_SIZE);\n+\t}\n+\n+\tnb_queues = RTE_MAX(dev->data->nb_rx_queues, dev->data->nb_tx_queues);\n+\tret = virtio_set_multiple_queues_rss(dev, nb_queues);\n+\tif (ret < 0) {\n+\t\tPMD_INIT_LOG(ERR, \"Failed to apply new RSS config to the device\");\n+\t\tgoto restore_key;\n+\t}\n+\n+\treturn 0;\n+restore_key:\n+\tmemcpy(hw->rss_key, old_rss_key, VIRTIO_NET_RSS_KEY_SIZE);\n+restore_types:\n+\thw->rss_hash_types = old_hash_types;\n+\n+\treturn ret;\n+}\n+\n+static int\n+virtio_dev_rss_hash_conf_get(struct rte_eth_dev *dev,\n+\t\tstruct rte_eth_rss_conf *rss_conf)\n+{\n+\tstruct virtio_hw *hw = dev->data->dev_private;\n+\n+\tif (!virtio_with_feature(hw, VIRTIO_NET_F_RSS))\n+\t\treturn -ENOTSUP;\n+\n+\tif (rss_conf->rss_key && rss_conf->rss_key_len >= VIRTIO_NET_RSS_KEY_SIZE)\n+\t\tmemcpy(rss_conf->rss_key, hw->rss_key, VIRTIO_NET_RSS_KEY_SIZE);\n+\trss_conf->rss_key_len = VIRTIO_NET_RSS_KEY_SIZE;\n+\trss_conf->rss_hf = virtio_to_ethdev_rss_offloads(hw->rss_hash_types);\n+\n+\treturn 0;\n+}\n+\n+static int virtio_dev_rss_reta_update(struct rte_eth_dev *dev,\n+\t\t\t struct rte_eth_rss_reta_entry64 *reta_conf,\n+\t\t\t uint16_t reta_size)\n+{\n+\tstruct virtio_hw *hw = dev->data->dev_private;\n+\tuint16_t nb_queues;\n+\tuint16_t old_reta[VIRTIO_NET_RSS_RETA_SIZE];\n+\tint idx, pos, i, ret;\n+\n+\tif (!virtio_with_feature(hw, VIRTIO_NET_F_RSS))\n+\t\treturn -ENOTSUP;\n+\n+\tif (reta_size != VIRTIO_NET_RSS_RETA_SIZE)\n+\t\treturn -EINVAL;\n+\n+\tmemcpy(old_reta, hw->rss_reta, sizeof(old_reta));\n+\n+\tfor (i = 0; i < reta_size; i++) {\n+\t\tidx = i / RTE_ETH_RETA_GROUP_SIZE;\n+\t\tpos = i % RTE_ETH_RETA_GROUP_SIZE;\n+\n+\t\tif (((reta_conf[idx].mask >> pos) & 0x1) == 0)\n+\t\t\tcontinue;\n+\n+\t\thw->rss_reta[i] = reta_conf[idx].reta[pos];\n+\t}\n+\n+\tnb_queues = RTE_MAX(dev->data->nb_rx_queues, dev->data->nb_tx_queues);\n+\tret = virtio_set_multiple_queues_rss(dev, nb_queues);\n+\tif (ret < 0) {\n+\t\tPMD_INIT_LOG(ERR, \"Failed to apply new RETA to the device\");\n+\t\tmemcpy(hw->rss_reta, old_reta, sizeof(old_reta));\n+\t}\n+\n+\thw->rss_rx_queues = dev->data->nb_rx_queues;\n+\n+\treturn ret;\n+}\n+\n+static int virtio_dev_rss_reta_query(struct rte_eth_dev *dev,\n+\t\t\t struct rte_eth_rss_reta_entry64 *reta_conf,\n+\t\t\t uint16_t reta_size)\n+{\n+\tstruct virtio_hw *hw = dev->data->dev_private;\n+\tint idx, i;\n+\n+\tif (!virtio_with_feature(hw, VIRTIO_NET_F_RSS))\n+\t\treturn -ENOTSUP;\n+\n+\tif (reta_size != VIRTIO_NET_RSS_RETA_SIZE)\n+\t\treturn -EINVAL;\n+\n+\tfor (i = 0; i < reta_size; i++) {\n+\t\tidx = i / RTE_ETH_RETA_GROUP_SIZE;\n+\t\treta_conf[idx].reta[i % RTE_ETH_RETA_GROUP_SIZE] = hw->rss_reta[i];\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * As default RSS hash key, it uses the default key of the\n+ * Intel IXGBE devices. It can be updated by the application\n+ * with any 40B key value.\n+ */\n+static uint8_t rss_intel_key[VIRTIO_NET_RSS_KEY_SIZE] = {\n+\t0x6D, 0x5A, 0x56, 0xDA, 0x25, 0x5B, 0x0E, 0xC2,\n+\t0x41, 0x67, 0x25, 0x3D, 0x43, 0xA3, 0x8F, 0xB0,\n+\t0xD0, 0xCA, 0x2B, 0xCB, 0xAE, 0x7B, 0x30, 0xB4,\n+\t0x77, 0xCB, 0x2D, 0xA3, 0x80, 0x30, 0xF2, 0x0C,\n+\t0x6A, 0x42, 0xB7, 0x3B, 0xBE, 0xAC, 0x01, 0xFA,\n+};\n+\n+static int\n+virtio_dev_rss_init(struct rte_eth_dev *eth_dev)\n+{\n+\tstruct virtio_hw *hw = eth_dev->data->dev_private;\n+\tuint16_t nb_rx_queues = eth_dev->data->nb_rx_queues;\n+\tstruct rte_eth_rss_conf *rss_conf;\n+\tint ret, i;\n+\n+\tif (!nb_rx_queues) {\n+\t\tPMD_INIT_LOG(ERR, \"Cannot init RSS if no Rx queues\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\trss_conf = &eth_dev->data->dev_conf.rx_adv_conf.rss_conf;\n+\n+\tret = virtio_dev_get_rss_config(hw, &hw->rss_hash_types);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (rss_conf->rss_hf) {\n+\t\t/*  Ensure requested hash types are supported by the device */\n+\t\tif (rss_conf->rss_hf & ~virtio_to_ethdev_rss_offloads(hw->rss_hash_types))\n+\t\t\treturn -EINVAL;\n+\n+\t\thw->rss_hash_types = ethdev_to_virtio_rss_offloads(rss_conf->rss_hf);\n+\t}\n+\n+\tif (!hw->rss_key) {\n+\t\t/* Setup default RSS key if not already setup by the user */\n+\t\thw->rss_key = rte_malloc_socket(\"rss_key\",\n+\t\t\t\tVIRTIO_NET_RSS_KEY_SIZE, 0,\n+\t\t\t\teth_dev->device->numa_node);\n+\t\tif (!hw->rss_key) {\n+\t\t\tPMD_INIT_LOG(ERR, \"Failed to allocate RSS key\");\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\n+\tif (rss_conf->rss_key && rss_conf->rss_key_len) {\n+\t\tif (rss_conf->rss_key_len != VIRTIO_NET_RSS_KEY_SIZE) {\n+\t\t\tPMD_INIT_LOG(ERR, \"Driver only supports %u RSS key length\",\n+\t\t\t\t\tVIRTIO_NET_RSS_KEY_SIZE);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t\tmemcpy(hw->rss_key, rss_conf->rss_key, VIRTIO_NET_RSS_KEY_SIZE);\n+\t} else {\n+\t\tmemcpy(hw->rss_key, rss_intel_key, VIRTIO_NET_RSS_KEY_SIZE);\n+\t}\n+\n+\tif (!hw->rss_reta) {\n+\t\t/* Setup default RSS reta if not already setup by the user */\n+\t\thw->rss_reta = rte_zmalloc_socket(\"rss_reta\",\n+\t\t\t\tVIRTIO_NET_RSS_RETA_SIZE * sizeof(uint16_t), 0,\n+\t\t\t\teth_dev->device->numa_node);\n+\t\tif (!hw->rss_reta) {\n+\t\t\tPMD_INIT_LOG(ERR, \"Failed to allocate RSS reta\");\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\thw->rss_rx_queues = 0;\n+\t}\n+\n+\t/* Re-initialize the RSS reta if the number of RX queues has changed */\n+\tif (hw->rss_rx_queues != nb_rx_queues) {\n+\t\tfor (i = 0; i < VIRTIO_NET_RSS_RETA_SIZE; i++)\n+\t\t\thw->rss_reta[i] = i % nb_rx_queues;\n+\t\thw->rss_rx_queues = nb_rx_queues;\n+\t}\n+\n+\treturn 0;\n+}\n+\n #define DUPLEX_UNKNOWN   0xff\n /* reset device and renegotiate features if needed */\n static int\n@@ -1805,14 +2199,15 @@ virtio_init_device(struct rte_eth_dev *eth_dev, uint64_t req_features)\n \t\t\tconfig->status = 0;\n \t\t}\n \n-\t\tif (virtio_with_feature(hw, VIRTIO_NET_F_MQ)) {\n+\t\tif (virtio_with_feature(hw, VIRTIO_NET_F_MQ) ||\n+\t\t\t\tvirtio_with_feature(hw, VIRTIO_NET_F_RSS)) {\n \t\t\tvirtio_read_dev_config(hw,\n \t\t\t\toffsetof(struct virtio_net_config, max_virtqueue_pairs),\n \t\t\t\t&config->max_virtqueue_pairs,\n \t\t\t\tsizeof(config->max_virtqueue_pairs));\n \t\t} else {\n \t\t\tPMD_INIT_LOG(DEBUG,\n-\t\t\t\t     \"VIRTIO_NET_F_MQ is not supported\");\n+\t\t\t\t     \"Neither VIRTIO_NET_F_MQ nor VIRTIO_NET_F_RSS are supported\");\n \t\t\tconfig->max_virtqueue_pairs = 1;\n \t\t}\n \n@@ -1844,6 +2239,11 @@ virtio_init_device(struct rte_eth_dev *eth_dev, uint64_t req_features)\n \t\t\t\tVLAN_TAG_LEN - hw->vtnet_hdr_size;\n \t\t}\n \n+\t\thw->rss_hash_types = 0;\n+\t\tif (virtio_with_feature(hw, VIRTIO_NET_F_RSS))\n+\t\t\tif (virtio_dev_rss_init(eth_dev))\n+\t\t\t\treturn -1;\n+\n \t\tPMD_INIT_LOG(DEBUG, \"config->max_virtqueue_pairs=%d\",\n \t\t\t\tconfig->max_virtqueue_pairs);\n \t\tPMD_INIT_LOG(DEBUG, \"config->status=%d\", config->status);\n@@ -2086,7 +2486,7 @@ virtio_dev_configure(struct rte_eth_dev *dev)\n \tPMD_INIT_LOG(DEBUG, \"configure\");\n \treq_features = VIRTIO_PMD_DEFAULT_GUEST_FEATURES;\n \n-\tif (rxmode->mq_mode != RTE_ETH_MQ_RX_NONE) {\n+\tif (rxmode->mq_mode != RTE_ETH_MQ_RX_NONE && rxmode->mq_mode != RTE_ETH_MQ_RX_RSS) {\n \t\tPMD_DRV_LOG(ERR,\n \t\t\t\"Unsupported Rx multi queue mode %d\",\n \t\t\trxmode->mq_mode);\n@@ -2106,6 +2506,9 @@ virtio_dev_configure(struct rte_eth_dev *dev)\n \t\t\treturn ret;\n \t}\n \n+\tif (rxmode->mq_mode == RTE_ETH_MQ_RX_RSS)\n+\t\treq_features |= (1ULL << VIRTIO_NET_F_RSS);\n+\n \tif (rxmode->mtu > hw->max_mtu)\n \t\treq_features &= ~(1ULL << VIRTIO_NET_F_MTU);\n \n@@ -2136,6 +2539,12 @@ virtio_dev_configure(struct rte_eth_dev *dev)\n \t\t\treturn ret;\n \t}\n \n+\tif ((rxmode->mq_mode & RTE_ETH_MQ_RX_RSS_FLAG) &&\n+\t\t\t!virtio_with_feature(hw, VIRTIO_NET_F_RSS)) {\n+\t\tPMD_DRV_LOG(ERR, \"RSS support requested but not supported by the device\");\n+\t\treturn -ENOTSUP;\n+\t}\n+\n \tif ((rx_offloads & (RTE_ETH_RX_OFFLOAD_UDP_CKSUM |\n \t\t\t    RTE_ETH_RX_OFFLOAD_TCP_CKSUM)) &&\n \t\t!virtio_with_feature(hw, VIRTIO_NET_F_GUEST_CSUM)) {\n@@ -2533,6 +2942,7 @@ static int\n virtio_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)\n {\n \tuint64_t tso_mask, host_features;\n+\tuint32_t rss_hash_types = 0;\n \tstruct virtio_hw *hw = dev->data->dev_private;\n \tdev_info->speed_capa = virtio_dev_speed_capa_get(hw->speed);\n \n@@ -2573,6 +2983,18 @@ virtio_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)\n \tif ((host_features & tso_mask) == tso_mask)\n \t\tdev_info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_TCP_TSO;\n \n+\tif (host_features & (1ULL << VIRTIO_NET_F_RSS)) {\n+\t\tvirtio_dev_get_rss_config(hw, &rss_hash_types);\n+\t\tdev_info->hash_key_size = VIRTIO_NET_RSS_KEY_SIZE;\n+\t\tdev_info->reta_size = VIRTIO_NET_RSS_RETA_SIZE;\n+\t\tdev_info->flow_type_rss_offloads =\n+\t\t\tvirtio_to_ethdev_rss_offloads(rss_hash_types);\n+\t} else {\n+\t\tdev_info->hash_key_size = 0;\n+\t\tdev_info->reta_size = 0;\n+\t\tdev_info->flow_type_rss_offloads = 0;\n+\t}\n+\n \tif (host_features & (1ULL << VIRTIO_F_RING_PACKED)) {\n \t\t/*\n \t\t * According to 2.7 Packed Virtqueues,\ndiff --git a/drivers/net/virtio/virtio_ethdev.h b/drivers/net/virtio/virtio_ethdev.h\nindex 40be484218..c08f382791 100644\n--- a/drivers/net/virtio/virtio_ethdev.h\n+++ b/drivers/net/virtio/virtio_ethdev.h\n@@ -45,7 +45,8 @@\n \t 1u << VIRTIO_NET_F_GUEST_TSO6     |\t\\\n \t 1u << VIRTIO_NET_F_CSUM           |\t\\\n \t 1u << VIRTIO_NET_F_HOST_TSO4      |\t\\\n-\t 1u << VIRTIO_NET_F_HOST_TSO6)\n+\t 1u << VIRTIO_NET_F_HOST_TSO6      |\t\\\n+\t 1ULL << VIRTIO_NET_F_RSS)\n \n extern const struct eth_dev_ops virtio_user_secondary_eth_dev_ops;\n \ndiff --git a/drivers/net/virtio/virtqueue.h b/drivers/net/virtio/virtqueue.h\nindex 97fc264e46..855f57a956 100644\n--- a/drivers/net/virtio/virtqueue.h\n+++ b/drivers/net/virtio/virtqueue.h\n@@ -201,6 +201,28 @@ struct virtio_net_ctrl_mac {\n #define VIRTIO_NET_CTRL_VLAN_ADD 0\n #define VIRTIO_NET_CTRL_VLAN_DEL 1\n \n+/**\n+ * RSS control\n+ *\n+ * The RSS feature configuration message is sent by the driver when\n+ * VIRTIO_NET_F_RSS has been negotiated. It provides the device with\n+ * hash types to use, hash key and indirection table. In this\n+ * implementation, the driver only supports fixed key length (40B)\n+ * and indirection table size (128 entries).\n+ */\n+#define VIRTIO_NET_RSS_RETA_SIZE 128\n+#define VIRTIO_NET_RSS_KEY_SIZE 40\n+\n+struct virtio_net_ctrl_rss {\n+\tuint32_t hash_types;\n+\tuint16_t indirection_table_mask;\n+\tuint16_t unclassified_queue;\n+\tuint16_t indirection_table[VIRTIO_NET_RSS_RETA_SIZE];\n+\tuint16_t max_tx_vq;\n+\tuint8_t hash_key_length;\n+\tuint8_t hash_key_data[VIRTIO_NET_RSS_KEY_SIZE];\n+};\n+\n /*\n  * Control link announce acknowledgement\n  *\n@@ -292,7 +314,10 @@ struct virtqueue {\n \n /* If multiqueue is provided by host, then we suppport it. */\n #define VIRTIO_NET_CTRL_MQ   4\n+\n #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET        0\n+#define VIRTIO_NET_CTRL_MQ_RSS_CONFIG          1\n+\n #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN        1\n #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX        0x8000\n \n",
    "prefixes": [
        "v6",
        "1/5"
    ]
}