From patchwork Tue Jun 16 06:45:12 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Wang X-Patchwork-Id: 280429 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=-6.5 required=3.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS autolearn=ham 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 18FFAC433DF for ; Tue, 16 Jun 2020 06:48:48 +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 CB8C820734 for ; Tue, 16 Jun 2020 06:48:47 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="ZWAEMN9q" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org CB8C820734 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:42768 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jl5Oo-0003Ev-Oc for qemu-devel@archiver.kernel.org; Tue, 16 Jun 2020 02:48:46 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:41814) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jl5MA-0001TH-Od for qemu-devel@nongnu.org; Tue, 16 Jun 2020 02:46:03 -0400 Received: from us-smtp-2.mimecast.com ([207.211.31.81]:34639 helo=us-smtp-delivery-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.90_1) (envelope-from ) id 1jl5M7-0005Xb-M4 for qemu-devel@nongnu.org; Tue, 16 Jun 2020 02:46:02 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1592289957; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:content-type:content-type:in-reply-to:in-reply-to: references:references; bh=9bA7F3hSzB73IAYUXkpPNuTolov5CpN8mAWqZoISKQY=; b=ZWAEMN9qtD4hahOeEoYQAjv2fzHY86OS69MsQEM7zAjGkN8gDeNt9f6nYeRkrJU6Ol3bBv fvW/o3Qf2l9MJzC+AxhLoVg5XEYHNrepKfYS3UX+hj2eO9yBBMbJGWT15IlHt1dQD+WQy3 nmaVV8X8PnmQw1nM7Bnq3oVZGfQdFUs= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-237-SnDZQfniNkufGHicKR8lZw-1; Tue, 16 Jun 2020 02:45:53 -0400 X-MC-Unique: SnDZQfniNkufGHicKR8lZw-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 519171138300; Tue, 16 Jun 2020 06:45:52 +0000 (UTC) Received: from jason-ThinkPad-T430s.redhat.com (ovpn-13-222.pek2.redhat.com [10.72.13.222]) by smtp.corp.redhat.com (Postfix) with ESMTP id A55FF90341; Tue, 16 Jun 2020 06:45:50 +0000 (UTC) From: Jason Wang To: peter.maydell@linaro.org Subject: [PULL 01/33] virtio-net: implement RSS configuration command Date: Tue, 16 Jun 2020 14:45:12 +0800 Message-Id: <1592289944-13727-2-git-send-email-jasowang@redhat.com> In-Reply-To: <1592289944-13727-1-git-send-email-jasowang@redhat.com> References: <1592289944-13727-1-git-send-email-jasowang@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Received-SPF: pass client-ip=207.211.31.81; envelope-from=jasowang@redhat.com; helo=us-smtp-delivery-1.mimecast.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/06/16 02:45:57 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] [fuzzy] X-Spam_score_int: -30 X-Spam_score: -3.1 X-Spam_bar: --- X-Spam_report: (-3.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H4=-0.01, RCVD_IN_MSPIKE_WL=-0.01, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=_AUTOLEARN X-Spam_action: no action 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: Yuri Benditovich , Jason Wang , qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Yuri Benditovich Optionally report RSS feature. Handle RSS configuration command and keep RSS parameters in virtio-net device context. Signed-off-by: Yuri Benditovich Signed-off-by: Jason Wang --- hw/net/trace-events | 3 + hw/net/virtio-net.c | 167 ++++++++++++++++++++++++++++++++++++++--- include/hw/virtio/virtio-net.h | 13 ++++ 3 files changed, 174 insertions(+), 9 deletions(-) diff --git a/hw/net/trace-events b/hw/net/trace-events index e18f883..a00ef6d 100644 --- a/hw/net/trace-events +++ b/hw/net/trace-events @@ -381,6 +381,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(const char *msg, uint32_t value) "%s, value 0x%08x" +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 b7f3d1b..e803b0a 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -77,6 +77,16 @@ 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_TCPv4 | \ + VIRTIO_NET_RSS_HASH_TYPE_UDPv4 | \ + VIRTIO_NET_RSS_HASH_TYPE_IPv6 | \ + VIRTIO_NET_RSS_HASH_TYPE_TCPv6 | \ + VIRTIO_NET_RSS_HASH_TYPE_UDPv6 | \ + VIRTIO_NET_RSS_HASH_TYPE_IP_EX | \ + 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) @@ -108,6 +118,8 @@ static VirtIOFeature feature_sizes[] = { .end = endof(struct virtio_net_config, mtu)}, {.flags = 1ULL << VIRTIO_NET_F_SPEED_DUPLEX, .end = endof(struct virtio_net_config, duplex)}, + {.flags = 1ULL << VIRTIO_NET_F_RSS, + .end = endof(struct virtio_net_config, supported_hash_types)}, {} }; @@ -138,6 +150,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 = n->net_conf.duplex; + netcfg.rss_max_key_size = 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); } @@ -701,6 +718,7 @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features, return features; } + virtio_clear_feature(&features, VIRTIO_NET_F_RSS); features = vhost_net_get_features(get_vhost_net(nc->peer), features); vdev->backend_features = features; @@ -860,6 +878,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, @@ -1136,25 +1155,152 @@ static int virtio_net_handle_announce(VirtIONet *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 = false; +} + +static uint16_t virtio_net_handle_rss(VirtIONet *n, + struct iovec *iov, unsigned int iov_cnt) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(n); + struct virtio_net_rss_config cfg; + size_t s, offset = 0, size_get; + uint16_t queues, i; + struct { + uint16_t us; + uint8_t b; + } QEMU_PACKED temp; + const char *err_msg = ""; + uint32_t err_value = 0; + + if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_RSS)) { + err_msg = "RSS is not negotiated"; + goto error; + } + size_get = offsetof(struct virtio_net_rss_config, indirection_table); + s = iov_to_buf(iov, iov_cnt, offset, &cfg, size_get); + if (s != size_get) { + err_msg = "Short command buffer"; + err_value = (uint32_t)s; + goto error; + } + n->rss_data.hash_types = virtio_ldl_p(vdev, &cfg.hash_types); + n->rss_data.indirections_len = + virtio_lduw_p(vdev, &cfg.indirection_table_mask); + n->rss_data.indirections_len++; + if (!is_power_of_2(n->rss_data.indirections_len)) { + err_msg = "Invalid size of indirection table"; + err_value = n->rss_data.indirections_len; + goto error; + } + if (n->rss_data.indirections_len > VIRTIO_NET_RSS_MAX_TABLE_LEN) { + err_msg = "Too large indirection table"; + err_value = n->rss_data.indirections_len; + goto error; + } + n->rss_data.default_queue = + virtio_lduw_p(vdev, &cfg.unclassified_queue); + if (n->rss_data.default_queue >= n->max_queues) { + err_msg = "Invalid default queue"; + err_value = n->rss_data.default_queue; + goto error; + } + offset += size_get; + size_get = sizeof(uint16_t) * n->rss_data.indirections_len; + g_free(n->rss_data.indirections_table); + n->rss_data.indirections_table = g_malloc(size_get); + if (!n->rss_data.indirections_table) { + err_msg = "Can't allocate indirections table"; + err_value = n->rss_data.indirections_len; + goto error; + } + s = iov_to_buf(iov, iov_cnt, offset, + n->rss_data.indirections_table, size_get); + if (s != size_get) { + err_msg = "Short indirection table buffer"; + err_value = (uint32_t)s; + goto error; + } + for (i = 0; i < n->rss_data.indirections_len; ++i) { + uint16_t val = n->rss_data.indirections_table[i]; + n->rss_data.indirections_table[i] = virtio_lduw_p(vdev, &val); + } + offset += size_get; + size_get = sizeof(temp); + s = iov_to_buf(iov, iov_cnt, offset, &temp, size_get); + if (s != size_get) { + err_msg = "Can't get queues"; + err_value = (uint32_t)s; + goto error; + } + queues = virtio_lduw_p(vdev, &temp.us); + if (queues == 0 || queues > n->max_queues) { + err_msg = "Invalid number of queues"; + err_value = queues; + goto error; + } + if (temp.b > VIRTIO_NET_RSS_MAX_KEY_SIZE) { + err_msg = "Invalid key size"; + err_value = temp.b; + goto error; + } + if (!temp.b && n->rss_data.hash_types) { + err_msg = "No key provided"; + err_value = 0; + goto error; + } + if (!temp.b && !n->rss_data.hash_types) { + virtio_net_disable_rss(n); + return queues; + } + offset += size_get; + size_get = temp.b; + s = iov_to_buf(iov, iov_cnt, offset, n->rss_data.key, size_get); + if (s != size_get) { + err_msg = "Can get key buffer"; + err_value = (uint32_t)s; + goto error; + } + n->rss_data.enabled = true; + trace_virtio_net_rss_enable(n->rss_data.hash_types, + n->rss_data.indirections_len, + temp.b); + return queues; +error: + trace_virtio_net_rss_error(err_msg, err_value); + 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 = VIRTIO_DEVICE(n); - struct virtio_net_ctrl_mq mq; - size_t s; uint16_t queues; - s = iov_to_buf(iov, iov_cnt, 0, &mq, sizeof(mq)); - if (s != sizeof(mq)) { - return VIRTIO_NET_ERR; - } + virtio_net_disable_rss(n); + if (cmd == VIRTIO_NET_CTRL_MQ_RSS_CONFIG) { + queues = virtio_net_handle_rss(n, iov, iov_cnt); + } else if (cmd == VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) { + struct virtio_net_ctrl_mq mq; + size_t s; + if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_MQ)) { + return VIRTIO_NET_ERR; + } + s = iov_to_buf(iov, iov_cnt, 0, &mq, sizeof(mq)); + if (s != sizeof(mq)) { + return VIRTIO_NET_ERR; + } + queues = virtio_lduw_p(vdev, &mq.virtqueue_pairs); - if (cmd != VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) { + } else { return VIRTIO_NET_ERR; } - queues = 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 || @@ -3111,6 +3257,7 @@ static void virtio_net_device_unrealize(DeviceState *dev) g_free(n->vqs); qemu_del_nic(n->nic); virtio_net_rsc_cleanup(n); + g_free(n->rss_data.indirections_table); virtio_cleanup(vdev); } @@ -3212,6 +3359,8 @@ static Property virtio_net_properties[] = { 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 96c68d4..d3fad7c 100644 --- a/include/hw/virtio/virtio-net.h +++ b/include/hw/virtio/virtio-net.h @@ -126,6 +126,18 @@ 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 VirtioNetRssData { + bool enabled; + uint32_t hash_types; + uint8_t key[VIRTIO_NET_RSS_MAX_KEY_SIZE]; + uint16_t indirections_len; + uint16_t *indirections_table; + uint16_t default_queue; +} VirtioNetRssData; + typedef struct VirtIONetQueue { VirtQueue *rx_vq; VirtQueue *tx_vq; @@ -199,6 +211,7 @@ struct VirtIONet { bool failover; DeviceListener primary_listener; Notifier migration_state; + VirtioNetRssData rss_data; }; void virtio_net_set_netclient_name(VirtIONet *n, const char *name,