From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-3.5 required=3.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS,HTML_MESSAGE,INCLUDES_PATCH,MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=no autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 55A65C10F27 for ; Tue, 10 Mar 2020 10:31:08 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 0F73320727 for ; Tue, 10 Mar 2020 10:31:07 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=daynix-com.20150623.gappssmtp.com header.i=@daynix-com.20150623.gappssmtp.com header.b="whEWG63k" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 0F73320727 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=daynix.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:56848 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jBcAF-0003GE-4u for qemu-devel@archiver.kernel.org; Tue, 10 Mar 2020 06:31:07 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:33815) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jBc8w-0002Xv-CW for qemu-devel@nongnu.org; Tue, 10 Mar 2020 06:29:49 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jBc8t-000059-G3 for qemu-devel@nongnu.org; Tue, 10 Mar 2020 06:29:46 -0400 Received: from mail-yw1-xc44.google.com ([2607:f8b0:4864:20::c44]:42898) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1jBc8t-0008WH-9g for qemu-devel@nongnu.org; Tue, 10 Mar 2020 06:29:43 -0400 Received: by mail-yw1-xc44.google.com with SMTP id v138so13109580ywa.9 for ; Tue, 10 Mar 2020 03:29:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=daynix-com.20150623.gappssmtp.com; s=20150623; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=zkWl4OnIWpTBj3hEyR7WMFuLfPIyP4xT68y7IN8+wmU=; b=whEWG63kF6dT4fnHAtNz8bzHgKw5yWVQ92AQA0s6hLX9Ol3vzEbCyuRjnuedKi/OWq Q1Giy8cP3eVTXheCJxPve7zdHP50ZDOyktTwaxXtd/qqgx/9eFW+lR0l51WxApBsH1wJ y2K9bGiueM6OlDdaeUQ5/Cw5n788R4IHGBdgmq39AXZ5eg04CNwrqna4btVT9R0hh1xL gim28iypupRfruwK/f3ubIRDyCrC561jv0Q5GJFVAav4+Fd1Q6cyAfbtJh830tbFeoeQ PCXknjQ7MOwlpfiI8Bzg0+aYxcY1zQu7Ck2kdg7+SJWB4P4ZE8INTD9DmKU/jAw/UZBN s1JQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=zkWl4OnIWpTBj3hEyR7WMFuLfPIyP4xT68y7IN8+wmU=; b=f47QlS40I3N5W6IQWhmm1lIFiG0Q2lwsELBzMwxBFj/RISoE9ws7/YQ9vg9BwBEWtz 1wLQZSqjKvfF6SJlO8tzBj7r+EYy6T1i9Wcalfs+EwABQoyjFN+3ix/FgO4yXdUjEOlh SwcC/dX/f0XruXpoa0ksWRu6weJ474nCihpUYSrDThcyH0kRnz0nK+uzC0SvjHC8EsiH WnotCcl+Y6AaOyWxnKrSuIrFiKZx/cko5cUffki5yPakILaF1ehfjvIXGQ6XL+nhlOHF 1WSLi9WJ0YU4jb8CFnOpBm9HiRLYWWwwy1n504wGN5NaDD2ekk+4f0TXLMdPhUFl6zva Z9LQ== X-Gm-Message-State: ANhLgQ3vcGKKJQxDF9nw4swN+NLzKMQbB1v5hNFYCKn48ak9ogbiBsAk +Q5JDDWZq7MywI/1ZHUSbRmut7CTaKzYMdKuYJm59g== X-Google-Smtp-Source: ADFU+vsfakXt0INCrtGRlUKXHVY9Ma3kRE7Gr6fF7yrFDu7c0slqsDvxD3zN+5oNH0boq6IjiZU01Yt3RDlO+R383dE= X-Received: by 2002:a81:449:: with SMTP id 70mr21393127ywe.133.1583836182392; Tue, 10 Mar 2020 03:29:42 -0700 (PDT) MIME-Version: 1.0 References: <20200309083438.2389-1-yuri.benditovich@daynix.com> <20200309083438.2389-3-yuri.benditovich@daynix.com> <2da1f442-ae53-b7b8-5622-eb93c061eecd@redhat.com> In-Reply-To: <2da1f442-ae53-b7b8-5622-eb93c061eecd@redhat.com> From: Yuri Benditovich Date: Tue, 10 Mar 2020 12:29:32 +0200 Message-ID: Subject: Re: [PATCH v2 2/4] virtio-net: implement RSS configuration command To: Jason Wang Content-Type: multipart/alternative; boundary="00000000000008c4c205a07d994b" X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:4864:20::c44 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Yan Vugenfirer , qemu-devel@nongnu.org, "Michael S . Tsirkin" Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" --00000000000008c4c205a07d994b Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Tue, Mar 10, 2020 at 5:02 AM Jason Wang wrote: > > On 2020/3/9 =E4=B8=8B=E5=8D=884:34, Yuri Benditovich wrote: > > Optionally report RSS feature. > > Handle RSS configuration command and keep RSS parameters > > in virtio-net device context. > > > > Signed-off-by: Yuri Benditovich > > --- > > hw/net/trace-events | 3 + > > hw/net/virtio-net.c | 148 +++++++++++++++++++++++++++++++-= - > > include/hw/virtio/virtio-net.h | 11 +++ > > 3 files changed, 153 insertions(+), 9 deletions(-) > > > > diff --git a/hw/net/trace-events b/hw/net/trace-events > > index a1da98a643..9823480d91 100644 > > --- a/hw/net/trace-events > > +++ b/hw/net/trace-events > > @@ -371,6 +371,9 @@ virtio_net_announce_notify(void) "" > > virtio_net_announce_timer(int round) "%d" > > virtio_net_handle_announce(int round) "%d" > > virtio_net_post_load_device(void) > > +virtio_net_rss_disable(void) > > +virtio_net_rss_error(int error_case) "case %d" > > +virtio_net_rss_enable(uint32_t p1, uint16_t p2, uint8_t p3) "hashes > 0x%x, table of %d, key of %d" > > > > # tulip.c > > tulip_reg_write(uint64_t addr, const char *name, int size, uint64_t > val) "addr 0x%02"PRIx64" (%s) size %d value 0x%08"PRIx64 > > diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c > > index 9545b0e84f..27071eccd2 100644 > > --- a/hw/net/virtio-net.c > > +++ b/hw/net/virtio-net.c > > @@ -172,6 +172,16 @@ struct virtio_net_rss_config { > > tso/gso/gro 'off'. */ > > #define VIRTIO_NET_RSC_DEFAULT_INTERVAL 300000 > > > > +#define VIRTIO_NET_RSS_SUPPORTED_HASHES (VIRTIO_NET_RSS_HASH_TYPE_IPv4 > | \ > > + VIRTIO_NET_RSS_HASH_TYPE_TCPv= 4 > | \ > > + VIRTIO_NET_RSS_HASH_TYPE_UDPv= 4 > | \ > > + VIRTIO_NET_RSS_HASH_TYPE_IPv6 > | \ > > + VIRTIO_NET_RSS_HASH_TYPE_TCPv= 6 > | \ > > + VIRTIO_NET_RSS_HASH_TYPE_UDPv= 6 > | \ > > + VIRTIO_NET_RSS_HASH_TYPE_IP_E= X > | \ > > + > VIRTIO_NET_RSS_HASH_TYPE_TCP_EX | \ > > + > VIRTIO_NET_RSS_HASH_TYPE_UDP_EX) > > + > > /* temporary until standard header include it */ > > #if !defined(VIRTIO_NET_HDR_F_RSC_INFO) > > > > @@ -203,6 +213,8 @@ static VirtIOFeature feature_sizes[] =3D { > > .end =3D endof(struct virtio_net_config, mtu)}, > > {.flags =3D 1ULL << VIRTIO_NET_F_SPEED_DUPLEX, > > .end =3D endof(struct virtio_net_config, duplex)}, > > + {.flags =3D 1ULL << VIRTIO_NET_F_RSS, > > + .end =3D endof(struct virtio_net_config, supported_hash_types)}, > > {} > > }; > > > > @@ -233,6 +245,11 @@ static void virtio_net_get_config(VirtIODevice > *vdev, uint8_t *config) > > memcpy(netcfg.mac, n->mac, ETH_ALEN); > > virtio_stl_p(vdev, &netcfg.speed, n->net_conf.speed); > > netcfg.duplex =3D n->net_conf.duplex; > > + netcfg.rss_max_key_size =3D VIRTIO_NET_RSS_MAX_KEY_SIZE; > > + virtio_stw_p(vdev, &netcfg.rss_max_indirection_table_length, > > + VIRTIO_NET_RSS_MAX_TABLE_LEN); > > + virtio_stl_p(vdev, &netcfg.supported_hash_types, > > + VIRTIO_NET_RSS_SUPPORTED_HASHES); > > memcpy(config, &netcfg, n->config_size); > > } > > > > @@ -796,6 +813,7 @@ static uint64_t virtio_net_get_features(VirtIODevic= e > *vdev, uint64_t features, > > return features; > > } > > > > + virtio_clear_feature(&features, VIRTIO_NET_F_RSS); > > features =3D vhost_net_get_features(get_vhost_net(nc->peer), > features); > > vdev->backend_features =3D features; > > > > @@ -955,6 +973,7 @@ static void virtio_net_set_features(VirtIODevice > *vdev, uint64_t features) > > } > > > > virtio_net_set_multiqueue(n, > > + virtio_has_feature(features, > VIRTIO_NET_F_RSS) || > > virtio_has_feature(features, > VIRTIO_NET_F_MQ)); > > > > virtio_net_set_mrg_rx_bufs(n, > > @@ -1231,25 +1250,134 @@ static int virtio_net_handle_announce(VirtIONe= t > *n, uint8_t cmd, > > } > > } > > > > +static void virtio_net_disable_rss(VirtIONet *n) > > +{ > > + if (n->rss_data.enabled) { > > + trace_virtio_net_rss_disable(); > > + } > > + n->rss_data.enabled =3D false; > > +} > > + > > +static uint16_t virtio_net_handle_rss(VirtIONet *n, > > + struct iovec *iov, unsigned int > iov_cnt) > > +{ > > + VirtIODevice *vdev =3D VIRTIO_DEVICE(n); > > + struct virtio_net_rss_config cfg; > > + size_t s, offset =3D 0, size_get; > > + uint16_t queues, i; > > + struct { > > + uint16_t us; > > + uint8_t b; > > + } QEMU_PACKED temp; > > + int err; > > + > > + if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_RSS)) { > > + err =3D 1; > > + goto error; > > + } > > + size_get =3D offsetof(struct virtio_net_rss_config, > indirection_table); > > + s =3D iov_to_buf(iov, iov_cnt, offset, &cfg, size_get); > > + if (s !=3D size_get) { > > + err =3D 2; > > + goto error; > > + } > > + n->rss_data.hash_types =3D virtio_ldl_p(vdev, &cfg.hash_types); > > + n->rss_data.indirections_len =3D > > + virtio_lduw_p(vdev, &cfg.indirection_table_mask); > > + n->rss_data.indirections_len++; > > + if (!is_power_of_2(n->rss_data.indirections_len)) { > > + err =3D 3; > > + goto error; > > + } > > + if (n->rss_data.indirections_len > VIRTIO_NET_RSS_MAX_TABLE_LEN) { > > + err =3D 4; > > + goto error; > > + } > > + n->rss_data.default_queue =3D > > + virtio_lduw_p(vdev, &cfg.unclassified_queue); > > + if (n->rss_data.default_queue >=3D n->max_queues) { > > + err =3D 5; > > + goto error; > > + } > > + offset +=3D size_get; > > + size_get =3D sizeof(uint16_t) * n->rss_data.indirections_len; > > + s =3D iov_to_buf(iov, iov_cnt, offset, n->rss_data.indirections, > size_get); > > + if (s !=3D size_get) { > > + err =3D 10; > > + goto error; > > + } > > + for (i =3D 0; i < n->rss_data.indirections_len; ++i) { > > + uint16_t val =3D n->rss_data.indirections[i]; > > + n->rss_data.indirections[i] =3D virtio_lduw_p(vdev, &val); > > + } > > + offset +=3D size_get; > > + size_get =3D sizeof(temp); > > + s =3D iov_to_buf(iov, iov_cnt, offset, &temp, size_get); > > + if (s !=3D size_get) { > > + err =3D 11; > > + goto error; > > + } > > + queues =3D virtio_lduw_p(vdev, &temp.us); > > + if (queues =3D=3D 0 || queues > n->max_queues) { > > + err =3D 12; > > + goto error; > > + } > > + if (temp.b > VIRTIO_NET_RSS_MAX_KEY_SIZE) { > > + err =3D 13; > > + goto error; > > + } > > + if (!temp.b && n->rss_data.hash_types) { > > + err =3D 20; > > + goto error; > > + } > > + if (!temp.b && !n->rss_data.hash_types) { > > + virtio_net_disable_rss(n); > > + return queues; > > + } > > + offset +=3D size_get; > > + size_get =3D temp.b; > > + s =3D iov_to_buf(iov, iov_cnt, offset, n->rss_data.key, size_get); > > + if (s !=3D size_get) { > > + err =3D 21; > > + goto error; > > + } > > + n->rss_data.enabled =3D true; > > + trace_virtio_net_rss_enable(n->rss_data.hash_types, > > + n->rss_data.indirections_len, > > + temp.b); > > + return queues; > > +error: > > + warn_report("%s: error_case %d", __func__, err); > > > I'm not sure using warn_report() is good for such guest triggerable > behavior. > > > > + trace_virtio_net_rss_error(err); > > > It looks to me it would be better to be verbose here (show temp.b or othe= r) > > > > + virtio_net_disable_rss(n); > > + return 0; > > +} > > + > > static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd, > > struct iovec *iov, unsigned int > iov_cnt) > > { > > VirtIODevice *vdev =3D VIRTIO_DEVICE(n); > > - struct virtio_net_ctrl_mq mq; > > - size_t s; > > uint16_t queues; > > > > - s =3D iov_to_buf(iov, iov_cnt, 0, &mq, sizeof(mq)); > > - if (s !=3D sizeof(mq)) { > > - return VIRTIO_NET_ERR; > > - } > > + virtio_net_disable_rss(n); > > + if (cmd =3D=3D VIRTIO_NET_CTRL_MQ_RSS_CONFIG) { > > + queues =3D virtio_net_handle_rss(n, iov, iov_cnt); > > + } else if (cmd =3D=3D VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) { > > > It looks to me RSS and MQ are mutually exclusive, is this intentional? > No they are not. The device can support RSS or MQ or both. The driver can activate multiqueue by VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET. The driver can activate multiqueue by VIRTIO_NET_CTRL_MQ_RSS_CONFIG . > > > > + struct virtio_net_ctrl_mq mq; > > + size_t s; > > + if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_MQ)) { > > + return VIRTIO_NET_ERR; > > + } > > + s =3D iov_to_buf(iov, iov_cnt, 0, &mq, sizeof(mq)); > > + if (s !=3D sizeof(mq)) { > > + return VIRTIO_NET_ERR; > > + } > > + queues =3D virtio_lduw_p(vdev, &mq.virtqueue_pairs); > > > > - if (cmd !=3D VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) { > > + } else { > > return VIRTIO_NET_ERR; > > } > > > > - queues =3D virtio_lduw_p(vdev, &mq.virtqueue_pairs); > > - > > if (queues < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN || > > queues > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX || > > queues > n->max_queues || > > @@ -3304,6 +3432,8 @@ static Property virtio_net_properties[] =3D { > > DEFINE_PROP_BIT64("ctrl_guest_offloads", VirtIONet, host_features= , > > VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, true), > > DEFINE_PROP_BIT64("mq", VirtIONet, host_features, VIRTIO_NET_F_MQ= , > false), > > + DEFINE_PROP_BIT64("rss", VirtIONet, host_features, > > + VIRTIO_NET_F_RSS, false), > > DEFINE_PROP_BIT64("guest_rsc_ext", VirtIONet, host_features, > > VIRTIO_NET_F_RSC_EXT, false), > > DEFINE_PROP_UINT32("rsc_interval", VirtIONet, rsc_timeout, > > diff --git a/include/hw/virtio/virtio-net.h > b/include/hw/virtio/virtio-net.h > > index 96c68d4a92..cf16f5192e 100644 > > --- a/include/hw/virtio/virtio-net.h > > +++ b/include/hw/virtio/virtio-net.h > > @@ -126,6 +126,9 @@ typedef struct VirtioNetRscChain { > > /* Maximum packet size we can receive from tap device: header + 64k *= / > > #define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 * > KiB)) > > > > +#define VIRTIO_NET_RSS_MAX_KEY_SIZE 40 > > +#define VIRTIO_NET_RSS_MAX_TABLE_LEN 128 > > + > > typedef struct VirtIONetQueue { > > VirtQueue *rx_vq; > > VirtQueue *tx_vq; > > @@ -199,6 +202,14 @@ struct VirtIONet { > > bool failover; > > DeviceListener primary_listener; > > Notifier migration_state; > > + struct { > > + bool enabled; > > + uint32_t hash_types; > > + uint8_t key[VIRTIO_NET_RSS_MAX_KEY_SIZE]; > > + uint16_t indirections[VIRTIO_NET_RSS_MAX_TABLE_LEN]; > > + uint16_t indirections_len; > > + uint16_t default_queue; > > + } rss_data; > > }; > > > > void virtio_net_set_netclient_name(VirtIONet *n, const char *name, > > --00000000000008c4c205a07d994b Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable


=
On Tue, Mar 10, 2020 at 5:02 AM Jason= Wang <jasowang@redhat.com>= ; wrote:

On 2020/3/9 =E4=B8=8B=E5=8D=884:34, Yuri Benditovich wrote:
> Optionally report RSS feature.
> Handle RSS configuration command and keep RSS parameters
> in virtio-net device context.
>
> Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
> ---
>=C2=A0 =C2=A0hw/net/trace-events=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 |=C2=A0 =C2=A03 +
>=C2=A0 =C2=A0hw/net/virtio-net.c=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 | 148 +++++++++++++++++++++++++++++++--
>=C2=A0 =C2=A0include/hw/virtio/virtio-net.h |=C2=A0 11 +++
>=C2=A0 =C2=A03 files changed, 153 insertions(+), 9 deletions(-)
>
> diff --git a/hw/net/trace-events b/hw/net/trace-events
> index a1da98a643..9823480d91 100644
> --- a/hw/net/trace-events
> +++ b/hw/net/trace-events
> @@ -371,6 +371,9 @@ virtio_net_announce_notify(void) ""
>=C2=A0 =C2=A0virtio_net_announce_timer(int round) "%d"
>=C2=A0 =C2=A0virtio_net_handle_announce(int round) "%d"
>=C2=A0 =C2=A0virtio_net_post_load_device(void)
> +virtio_net_rss_disable(void)
> +virtio_net_rss_error(int error_case) "case %d"
> +virtio_net_rss_enable(uint32_t p1, uint16_t p2, uint8_t p3) "has= hes 0x%x, table of %d, key of %d"
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0# tulip.c
>=C2=A0 =C2=A0tulip_reg_write(uint64_t addr, const char *name, int size,= uint64_t val) "addr 0x%02"PRIx64" (%s) size %d value 0x%08&= quot;PRIx64
> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> index 9545b0e84f..27071eccd2 100644
> --- a/hw/net/virtio-net.c
> +++ b/hw/net/virtio-net.c
> @@ -172,6 +172,16 @@ struct virtio_net_rss_config {
>=C2=A0 =C2=A0 =C2=A0 tso/gso/gro 'off'. */
>=C2=A0 =C2=A0#define VIRTIO_NET_RSC_DEFAULT_INTERVAL 300000
>=C2=A0 =C2=A0
> +#define VIRTIO_NET_RSS_SUPPORTED_HASHES (VIRTIO_NET_RSS_HASH_TYPE_IPv= 4 | \
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0VIRTIO_NET_RSS_HASH_TYPE_TCPv4 | \
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0VIRTIO_NET_RSS_HASH_TYPE_UDPv4 | \
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0VIRTIO_NET_RSS_HASH_TYPE_IPv6 | \
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0VIRTIO_NET_RSS_HASH_TYPE_TCPv6 | \
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0VIRTIO_NET_RSS_HASH_TYPE_UDPv6 | \
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0VIRTIO_NET_RSS_HASH_TYPE_IP_EX | \
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0VIRTIO_NET_RSS_HASH_TYPE_TCP_EX | \
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0VIRTIO_NET_RSS_HASH_TYPE_UDP_EX)
> +
>=C2=A0 =C2=A0/* temporary until standard header include it */
>=C2=A0 =C2=A0#if !defined(VIRTIO_NET_HDR_F_RSC_INFO)
>=C2=A0 =C2=A0
> @@ -203,6 +213,8 @@ static VirtIOFeature feature_sizes[] =3D {
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 .end =3D endof(struct virtio_net_config, mt= u)},
>=C2=A0 =C2=A0 =C2=A0 =C2=A0{.flags =3D 1ULL << VIRTIO_NET_F_SPEED= _DUPLEX,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 .end =3D endof(struct virtio_net_config, du= plex)},
> +=C2=A0 =C2=A0 {.flags =3D 1ULL << VIRTIO_NET_F_RSS,
> +=C2=A0 =C2=A0 =C2=A0.end =3D endof(struct virtio_net_config, supporte= d_hash_types)},
>=C2=A0 =C2=A0 =C2=A0 =C2=A0{}
>=C2=A0 =C2=A0};
>=C2=A0 =C2=A0
> @@ -233,6 +245,11 @@ static void virtio_net_get_config(VirtIODevice *v= dev, uint8_t *config)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0memcpy(netcfg.mac, n->mac, ETH_ALEN);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0virtio_stl_p(vdev, &netcfg.speed, n->= net_conf.speed);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0netcfg.duplex =3D n->net_conf.duplex;
> +=C2=A0 =C2=A0 netcfg.rss_max_key_size =3D VIRTIO_NET_RSS_MAX_KEY_SIZE= ;
> +=C2=A0 =C2=A0 virtio_stw_p(vdev, &netcfg.rss_max_indirection_tabl= e_length,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0VIRTIO_= NET_RSS_MAX_TABLE_LEN);
> +=C2=A0 =C2=A0 virtio_stl_p(vdev, &netcfg.supported_hash_types, > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0VIRTIO_= NET_RSS_SUPPORTED_HASHES);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0memcpy(config, &netcfg, n->config_siz= e);
>=C2=A0 =C2=A0}
>=C2=A0 =C2=A0
> @@ -796,6 +813,7 @@ static uint64_t virtio_net_get_features(VirtIODevi= ce *vdev, uint64_t features,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return features;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0}
>=C2=A0 =C2=A0
> +=C2=A0 =C2=A0 virtio_clear_feature(&features, VIRTIO_NET_F_RSS);<= br> >=C2=A0 =C2=A0 =C2=A0 =C2=A0features =3D vhost_net_get_features(get_vhos= t_net(nc->peer), features);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0vdev->backend_features =3D features;
>=C2=A0 =C2=A0
> @@ -955,6 +973,7 @@ static void virtio_net_set_features(VirtIODevice *= vdev, uint64_t features)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0}
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0 =C2=A0 =C2=A0virtio_net_set_multiqueue(n,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 virtio_has_feature(features, VIRTIO_NET= _F_RSS) ||
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0virtio_has_feature(features= , VIRTIO_NET_F_MQ));
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0 =C2=A0 =C2=A0virtio_net_set_mrg_rx_bufs(n,
> @@ -1231,25 +1250,134 @@ static int virtio_net_handle_announce(VirtION= et *n, uint8_t cmd,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0}
>=C2=A0 =C2=A0}
>=C2=A0 =C2=A0
> +static void virtio_net_disable_rss(VirtIONet *n)
> +{
> +=C2=A0 =C2=A0 if (n->rss_data.enabled) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 trace_virtio_net_rss_disable();
> +=C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 n->rss_data.enabled =3D false;
> +}
> +
> +static uint16_t virtio_net_handle_rss(VirtIONet *n,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 struct iove= c *iov, unsigned int iov_cnt)
> +{
> +=C2=A0 =C2=A0 VirtIODevice *vdev =3D VIRTIO_DEVICE(n);
> +=C2=A0 =C2=A0 struct virtio_net_rss_config cfg;
> +=C2=A0 =C2=A0 size_t s, offset =3D 0, size_get;
> +=C2=A0 =C2=A0 uint16_t queues, i;
> +=C2=A0 =C2=A0 struct {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 uint16_t us;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 uint8_t b;
> +=C2=A0 =C2=A0 } QEMU_PACKED temp;
> +=C2=A0 =C2=A0 int err;
> +
> +=C2=A0 =C2=A0 if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_RSS)) {=
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 err =3D 1;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error;
> +=C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 size_get =3D offsetof(struct virtio_net_rss_config, ind= irection_table);
> +=C2=A0 =C2=A0 s =3D iov_to_buf(iov, iov_cnt, offset, &cfg, size_g= et);
> +=C2=A0 =C2=A0 if (s !=3D size_get) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 err =3D 2;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error;
> +=C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 n->rss_data.hash_types =3D virtio_ldl_p(vdev, &c= fg.hash_types);
> +=C2=A0 =C2=A0 n->rss_data.indirections_len =3D
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 virtio_lduw_p(vdev, &cfg.indirection_= table_mask);
> +=C2=A0 =C2=A0 n->rss_data.indirections_len++;
> +=C2=A0 =C2=A0 if (!is_power_of_2(n->rss_data.indirections_len)) {<= br> > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 err =3D 3;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error;
> +=C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 if (n->rss_data.indirections_len > VIRTIO_NET_RSS= _MAX_TABLE_LEN) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 err =3D 4;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error;
> +=C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 n->rss_data.default_queue =3D
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 virtio_lduw_p(vdev, &cfg.unclassified= _queue);
> +=C2=A0 =C2=A0 if (n->rss_data.default_queue >=3D n->max_queu= es) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 err =3D 5;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error;
> +=C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 offset +=3D size_get;
> +=C2=A0 =C2=A0 size_get =3D sizeof(uint16_t) * n->rss_data.indirect= ions_len;
> +=C2=A0 =C2=A0 s =3D iov_to_buf(iov, iov_cnt, offset, n->rss_data.i= ndirections, size_get);
> +=C2=A0 =C2=A0 if (s !=3D size_get) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 err =3D 10;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error;
> +=C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 for (i =3D 0; i < n->rss_data.indirections_len; += +i) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 uint16_t val =3D n->rss_data.indirecti= ons[i];
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 n->rss_data.indirections[i] =3D virtio= _lduw_p(vdev, &val);
> +=C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 offset +=3D size_get;
> +=C2=A0 =C2=A0 size_get =3D sizeof(temp);
> +=C2=A0 =C2=A0 s =3D iov_to_buf(iov, iov_cnt, offset, &temp, size_= get);
> +=C2=A0 =C2=A0 if (s !=3D size_get) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 err =3D 11;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error;
> +=C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 queues =3D virtio_lduw_p(vdev, &temp.us);
> +=C2=A0 =C2=A0 if (queues =3D=3D 0 || queues > n->max_queues) {<= br> > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 err =3D 12;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error;
> +=C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 if (temp.b > VIRTIO_NET_RSS_MAX_KEY_SIZE) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 err =3D 13;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error;
> +=C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 if (!temp.b && n->rss_data.hash_types) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 err =3D 20;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error;
> +=C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 if (!temp.b && !n->rss_data.hash_types) { > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 virtio_net_disable_rss(n);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 return queues;
> +=C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 offset +=3D size_get;
> +=C2=A0 =C2=A0 size_get =3D temp.b;
> +=C2=A0 =C2=A0 s =3D iov_to_buf(iov, iov_cnt, offset, n->rss_data.k= ey, size_get);
> +=C2=A0 =C2=A0 if (s !=3D size_get) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 err =3D 21;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 goto error;
> +=C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 n->rss_data.enabled =3D true;
> +=C2=A0 =C2=A0 trace_virtio_net_rss_enable(n->rss_data.hash_types,<= br> > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 n->rss_data.indirections_len,=
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 temp.b);
> +=C2=A0 =C2=A0 return queues;
> +error:
> +=C2=A0 =C2=A0 warn_report("%s: error_case %d", __func__, er= r);


I'm not sure using warn_report() is good for such guest triggerable behavior.


> +=C2=A0 =C2=A0 trace_virtio_net_rss_error(err);


It looks to me it would be better to be verbose here (show temp.b or other)=


> +=C2=A0 =C2=A0 virtio_net_disable_rss(n);
> +=C2=A0 =C2=A0 return 0;
> +}
> +
>=C2=A0 =C2=A0static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd,=
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0struct iovec *iov, u= nsigned int iov_cnt)
>=C2=A0 =C2=A0{
>=C2=A0 =C2=A0 =C2=A0 =C2=A0VirtIODevice *vdev =3D VIRTIO_DEVICE(n);
> -=C2=A0 =C2=A0 struct virtio_net_ctrl_mq mq;
> -=C2=A0 =C2=A0 size_t s;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0uint16_t queues;
>=C2=A0 =C2=A0
> -=C2=A0 =C2=A0 s =3D iov_to_buf(iov, iov_cnt, 0, &mq, sizeof(mq));=
> -=C2=A0 =C2=A0 if (s !=3D sizeof(mq)) {
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 return VIRTIO_NET_ERR;
> -=C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 virtio_net_disable_rss(n);
> +=C2=A0 =C2=A0 if (cmd =3D=3D VIRTIO_NET_CTRL_MQ_RSS_CONFIG) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 queues =3D virtio_net_handle_rss(n, iov, = iov_cnt);
> +=C2=A0 =C2=A0 } else if (cmd =3D=3D VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) = {


It looks to me RSS and MQ are mutually exclusive, is this intentional?
<= /blockquote>

No they are not. The device can support RSS= or MQ or both.
The driver can activate multiqueue by VIRTIO_NET_= CTRL_MQ_VQ_PAIRS_SET.
The driver can activate multiqueue by=C2=A0 VIRTIO_NET_CTRL_MQ_RSS_CONFIG=C2=A0 .
=C2=A0
=C2=A0


> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 struct virtio_net_ctrl_mq mq;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 size_t s;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 if (!virtio_vdev_has_feature(vdev, VIRTIO= _NET_F_MQ)) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return VIRTIO_NET_ERR;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 s =3D iov_to_buf(iov, iov_cnt, 0, &mq= , sizeof(mq));
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 if (s !=3D sizeof(mq)) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return VIRTIO_NET_ERR;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 queues =3D virtio_lduw_p(vdev, &mq.vi= rtqueue_pairs);
>=C2=A0 =C2=A0
> -=C2=A0 =C2=A0 if (cmd !=3D VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) {
> +=C2=A0 =C2=A0 } else {
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return VIRTIO_NET_ERR;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0}
>=C2=A0 =C2=A0
> -=C2=A0 =C2=A0 queues =3D virtio_lduw_p(vdev, &mq.virtqueue_pairs)= ;
> -
>=C2=A0 =C2=A0 =C2=A0 =C2=A0if (queues < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_= MIN ||
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0queues > VIRTIO_NET_CTRL_MQ= _VQ_PAIRS_MAX ||
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0queues > n->max_queues |= |
> @@ -3304,6 +3432,8 @@ static Property virtio_net_properties[] =3D { >=C2=A0 =C2=A0 =C2=A0 =C2=A0DEFINE_PROP_BIT64("ctrl_guest_offloads&= quot;, VirtIONet, host_features,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, true),
>=C2=A0 =C2=A0 =C2=A0 =C2=A0DEFINE_PROP_BIT64("mq", VirtIONet,= host_features, VIRTIO_NET_F_MQ, false),
> +=C2=A0 =C2=A0 DEFINE_PROP_BIT64("rss", VirtIONet, host_feat= ures,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= VIRTIO_NET_F_RSS, false),
>=C2=A0 =C2=A0 =C2=A0 =C2=A0DEFINE_PROP_BIT64("guest_rsc_ext",= VirtIONet, host_features,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0VIRTIO_NET_F_RSC_EXT, false),
>=C2=A0 =C2=A0 =C2=A0 =C2=A0DEFINE_PROP_UINT32("rsc_interval",= VirtIONet, rsc_timeout,
> diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio= -net.h
> index 96c68d4a92..cf16f5192e 100644
> --- a/include/hw/virtio/virtio-net.h
> +++ b/include/hw/virtio/virtio-net.h
> @@ -126,6 +126,9 @@ typedef struct VirtioNetRscChain {
>=C2=A0 =C2=A0/* Maximum packet size we can receive from tap device: hea= der + 64k */
>=C2=A0 =C2=A0#define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_h= dr) + (64 * KiB))
>=C2=A0 =C2=A0
> +#define VIRTIO_NET_RSS_MAX_KEY_SIZE=C2=A0 =C2=A0 =C2=A040
> +#define VIRTIO_NET_RSS_MAX_TABLE_LEN=C2=A0 =C2=A0 128
> +
>=C2=A0 =C2=A0typedef struct VirtIONetQueue {
>=C2=A0 =C2=A0 =C2=A0 =C2=A0VirtQueue *rx_vq;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0VirtQueue *tx_vq;
> @@ -199,6 +202,14 @@ struct VirtIONet {
>=C2=A0 =C2=A0 =C2=A0 =C2=A0bool failover;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0DeviceListener primary_listener;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0Notifier migration_state;
> +=C2=A0 =C2=A0 struct {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 bool=C2=A0 =C2=A0 enabled;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 uint32_t hash_types;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 uint8_t key[VIRTIO_NET_RSS_MAX_KEY_SIZE];=
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 uint16_t indirections[VIRTIO_NET_RSS_MAX_= TABLE_LEN];
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 uint16_t indirections_len;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 uint16_t default_queue;
> +=C2=A0 =C2=A0 } rss_data;
>=C2=A0 =C2=A0};
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0void virtio_net_set_netclient_name(VirtIONet *n, const cha= r *name,

--00000000000008c4c205a07d994b--