From patchwork Tue Apr 23 11:31:34 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xuan Zhuo X-Patchwork-Id: 13639887 X-Patchwork-Delegate: kuba@kernel.org Received: from out30-111.freemail.mail.aliyun.com (out30-111.freemail.mail.aliyun.com [115.124.30.111]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6CB93762E8; Tue, 23 Apr 2024 11:31:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.30.111 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713871910; cv=none; b=GMaa23JOERCODCiTNc/6X0mLqgpm+Z296BEsmGOx8cVHNNkAoWQpew7v++dUuYUj+bBJyx71qAqoJXG6ZjWpKCcDvB9TFwXiZZSnUIFFaTtdOBFnE4xqB/H8rcHSPfAhTCqEw62KPrYaInZs7vOLap2o13K/PawKHtzFxaOfKJw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713871910; c=relaxed/simple; bh=TodF9TeWMpxYPKN93QRWe7nG2Pyh1EhsKHXuleHLSnA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=mOOS+l+GDKrQzPnr0+NMwH1ZdV0izaxOqnkmErVLB/Dj2B7MQmRbHH7uhn3t3eMfnppwqsn/+tuOBM/gxH0SgxxiRUquMqZzukcpQ4uDzRW351q2VcspBH63wULwI1DsADGNz1AcJRi4Y3ksoK9m/ZGv4xAN2D/Krz1S40rThG0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com; spf=pass smtp.mailfrom=linux.alibaba.com; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b=qbtNmhqZ; arc=none smtp.client-ip=115.124.30.111 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b="qbtNmhqZ" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1713871905; h=From:To:Subject:Date:Message-Id:MIME-Version; bh=//wF16EoJK4cWrREf4HMlhdqrpAHbS60oTEaoobU9Xs=; b=qbtNmhqZGAaPiCLpim44tO/reoCPZOlEyf1OhESHbZeG1+6rmHCRaHqATTruYp2xwZLOQvJaMcfzor08hmo808+osuhG7mDNe4ahEE3fUXXgWu+cZdXREhSEYxO6JQi4mvSwbmPVtGMpZ5hIMsiGr2oGKC7aCcFkTf2VrXVeCzs= X-Alimail-AntiSpam: AC=PASS;BC=-1|-1;BR=01201311R381e4;CH=green;DM=||false|;DS=||;FP=0|-1|-1|-1|0|-1|-1|-1;HT=ay29a033018045168;MF=xuanzhuo@linux.alibaba.com;NM=1;PH=DS;RN=19;SR=0;TI=SMTPD_---0W592gOK_1713871902; Received: from localhost(mailfrom:xuanzhuo@linux.alibaba.com fp:SMTPD_---0W592gOK_1713871902) by smtp.aliyun-inc.com; Tue, 23 Apr 2024 19:31:44 +0800 From: Xuan Zhuo To: netdev@vger.kernel.org Cc: "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , "Michael S. Tsirkin" , Jason Wang , Xuan Zhuo , Alexei Starovoitov , Daniel Borkmann , Jesper Dangaard Brouer , John Fastabend , Stanislav Fomichev , Amritha Nambiar , Larysa Zaremba , Sridhar Samudrala , Maciej Fijalkowski , virtualization@lists.linux.dev, bpf@vger.kernel.org Subject: [PATCH net-next v6 1/8] virtio_net: introduce device stats feature and structures Date: Tue, 23 Apr 2024 19:31:34 +0800 Message-Id: <20240423113141.1752-2-xuanzhuo@linux.alibaba.com> X-Mailer: git-send-email 2.32.0.3.g01195cf9f In-Reply-To: <20240423113141.1752-1-xuanzhuo@linux.alibaba.com> References: <20240423113141.1752-1-xuanzhuo@linux.alibaba.com> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Git-Hash: 75c95ace5f2d X-Patchwork-Delegate: kuba@kernel.org The virtio-net device stats spec: https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82 We introduce the relative feature and structures. Signed-off-by: Xuan Zhuo Acked-by: Jason Wang --- include/uapi/linux/virtio_net.h | 143 ++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/include/uapi/linux/virtio_net.h b/include/uapi/linux/virtio_net.h index cc65ef0f3c3e..ac9174717ef1 100644 --- a/include/uapi/linux/virtio_net.h +++ b/include/uapi/linux/virtio_net.h @@ -56,6 +56,7 @@ #define VIRTIO_NET_F_MQ 22 /* Device supports Receive Flow * Steering */ #define VIRTIO_NET_F_CTRL_MAC_ADDR 23 /* Set MAC address */ +#define VIRTIO_NET_F_DEVICE_STATS 50 /* Device can provide device-level statistics. */ #define VIRTIO_NET_F_VQ_NOTF_COAL 52 /* Device supports virtqueue notification coalescing */ #define VIRTIO_NET_F_NOTF_COAL 53 /* Device supports notifications coalescing */ #define VIRTIO_NET_F_GUEST_USO4 54 /* Guest can handle USOv4 in. */ @@ -406,4 +407,146 @@ struct virtio_net_ctrl_coal_vq { struct virtio_net_ctrl_coal coal; }; +/* + * Device Statistics + */ +#define VIRTIO_NET_CTRL_STATS 8 +#define VIRTIO_NET_CTRL_STATS_QUERY 0 +#define VIRTIO_NET_CTRL_STATS_GET 1 + +struct virtio_net_stats_capabilities { + +#define VIRTIO_NET_STATS_TYPE_CVQ (1ULL << 32) + +#define VIRTIO_NET_STATS_TYPE_RX_BASIC (1ULL << 0) +#define VIRTIO_NET_STATS_TYPE_RX_CSUM (1ULL << 1) +#define VIRTIO_NET_STATS_TYPE_RX_GSO (1ULL << 2) +#define VIRTIO_NET_STATS_TYPE_RX_SPEED (1ULL << 3) + +#define VIRTIO_NET_STATS_TYPE_TX_BASIC (1ULL << 16) +#define VIRTIO_NET_STATS_TYPE_TX_CSUM (1ULL << 17) +#define VIRTIO_NET_STATS_TYPE_TX_GSO (1ULL << 18) +#define VIRTIO_NET_STATS_TYPE_TX_SPEED (1ULL << 19) + + __le64 supported_stats_types[1]; +}; + +struct virtio_net_ctrl_queue_stats { + struct { + __le16 vq_index; + __le16 reserved[3]; + __le64 types_bitmap[1]; + } stats[1]; +}; + +struct virtio_net_stats_reply_hdr { +#define VIRTIO_NET_STATS_TYPE_REPLY_CVQ 32 + +#define VIRTIO_NET_STATS_TYPE_REPLY_RX_BASIC 0 +#define VIRTIO_NET_STATS_TYPE_REPLY_RX_CSUM 1 +#define VIRTIO_NET_STATS_TYPE_REPLY_RX_GSO 2 +#define VIRTIO_NET_STATS_TYPE_REPLY_RX_SPEED 3 + +#define VIRTIO_NET_STATS_TYPE_REPLY_TX_BASIC 16 +#define VIRTIO_NET_STATS_TYPE_REPLY_TX_CSUM 17 +#define VIRTIO_NET_STATS_TYPE_REPLY_TX_GSO 18 +#define VIRTIO_NET_STATS_TYPE_REPLY_TX_SPEED 19 + __u8 type; + __u8 reserved; + __le16 vq_index; + __le16 reserved1; + __le16 size; +}; + +struct virtio_net_stats_cvq { + struct virtio_net_stats_reply_hdr hdr; + + __le64 command_num; + __le64 ok_num; +}; + +struct virtio_net_stats_rx_basic { + struct virtio_net_stats_reply_hdr hdr; + + __le64 rx_notifications; + + __le64 rx_packets; + __le64 rx_bytes; + + __le64 rx_interrupts; + + __le64 rx_drops; + __le64 rx_drop_overruns; +}; + +struct virtio_net_stats_tx_basic { + struct virtio_net_stats_reply_hdr hdr; + + __le64 tx_notifications; + + __le64 tx_packets; + __le64 tx_bytes; + + __le64 tx_interrupts; + + __le64 tx_drops; + __le64 tx_drop_malformed; +}; + +struct virtio_net_stats_rx_csum { + struct virtio_net_stats_reply_hdr hdr; + + __le64 rx_csum_valid; + __le64 rx_needs_csum; + __le64 rx_csum_none; + __le64 rx_csum_bad; +}; + +struct virtio_net_stats_tx_csum { + struct virtio_net_stats_reply_hdr hdr; + + __le64 tx_csum_none; + __le64 tx_needs_csum; +}; + +struct virtio_net_stats_rx_gso { + struct virtio_net_stats_reply_hdr hdr; + + __le64 rx_gso_packets; + __le64 rx_gso_bytes; + __le64 rx_gso_packets_coalesced; + __le64 rx_gso_bytes_coalesced; +}; + +struct virtio_net_stats_tx_gso { + struct virtio_net_stats_reply_hdr hdr; + + __le64 tx_gso_packets; + __le64 tx_gso_bytes; + __le64 tx_gso_segments; + __le64 tx_gso_segments_bytes; + __le64 tx_gso_packets_noseg; + __le64 tx_gso_bytes_noseg; +}; + +struct virtio_net_stats_rx_speed { + struct virtio_net_stats_reply_hdr hdr; + + /* rx_{packets,bytes}_allowance_exceeded are too long. So rename to + * short name. + */ + __le64 rx_ratelimit_packets; + __le64 rx_ratelimit_bytes; +}; + +struct virtio_net_stats_tx_speed { + struct virtio_net_stats_reply_hdr hdr; + + /* tx_{packets,bytes}_allowance_exceeded are too long. So rename to + * short name. + */ + __le64 tx_ratelimit_packets; + __le64 tx_ratelimit_bytes; +}; + #endif /* _UAPI_LINUX_VIRTIO_NET_H */ From patchwork Tue Apr 23 11:31:35 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xuan Zhuo X-Patchwork-Id: 13639891 X-Patchwork-Delegate: kuba@kernel.org Received: from out30-124.freemail.mail.aliyun.com (out30-124.freemail.mail.aliyun.com [115.124.30.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E74EC84A40; Tue, 23 Apr 2024 11:31:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.30.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713871916; cv=none; b=h1ZE2Q5ioHmys1S3yiwe7N57hW2N1IOBeYkXnYVZzIvhi0mBNOuIGmii78reUkXEMfEf5ROX0iKkW6YHxd+OjA39UjyQt7Mhza+Tok6CbMUShKzERzxK+eISemPyk+jNTaZDdXJquIfKLwa3Q9RZ8rSHBal/Z0qIk8I4Jm7uofk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713871916; c=relaxed/simple; bh=q3ZyIgBmElYvqwygrKxU4CkdF4eQJwLkLTU61XautEs=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=TDXEJEC6ErAQf4TuIQBQWD1lbUIr7SgBK5OEuxLvQuDsjb6YxKLulfTX+7C/nXiBGXFY+xQQSYn3VeBQ+mxRYjHvPcKK6dzF5C1R7FypeXWv/5NvPymTLbDAx3WgQlcBr3sETLdvx0Mp1Dprs0Vy7yWJMAsZ24yyaKrQbJzk9UA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com; spf=pass smtp.mailfrom=linux.alibaba.com; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b=i4SDtJuD; arc=none smtp.client-ip=115.124.30.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b="i4SDtJuD" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1713871906; h=From:To:Subject:Date:Message-Id:MIME-Version; bh=NQb2rLSJ5HIC9zF/pW9mQ/XcCiSAq+Fis1uUOTIBIAM=; b=i4SDtJuDVeLK2oPzZxsXP2I4wPwXYFP/89ys8wlE/SUmFL10bCMxbYC8U1395wE1mUKKsHrLaPOkwdz2FVsw94COMIaHB9wVV2TGYxgCBc32id0nv8D+kkZBZFKUK3Z90NrzwREkbYUBQWGcSZhyMXfcC0BcLBfNCwHznC4Uu0c= X-Alimail-AntiSpam: AC=PASS;BC=-1|-1;BR=01201311R121e4;CH=green;DM=||false|;DS=||;FP=0|-1|-1|-1|0|-1|-1|-1;HT=ay29a033018045170;MF=xuanzhuo@linux.alibaba.com;NM=1;PH=DS;RN=19;SR=0;TI=SMTPD_---0W591Z6W_1713871904; Received: from localhost(mailfrom:xuanzhuo@linux.alibaba.com fp:SMTPD_---0W591Z6W_1713871904) by smtp.aliyun-inc.com; Tue, 23 Apr 2024 19:31:45 +0800 From: Xuan Zhuo To: netdev@vger.kernel.org Cc: "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , "Michael S. Tsirkin" , Jason Wang , Xuan Zhuo , Alexei Starovoitov , Daniel Borkmann , Jesper Dangaard Brouer , John Fastabend , Stanislav Fomichev , Amritha Nambiar , Larysa Zaremba , Sridhar Samudrala , Maciej Fijalkowski , virtualization@lists.linux.dev, bpf@vger.kernel.org Subject: [PATCH net-next v6 2/8] virtio_net: remove "_queue" from ethtool -S Date: Tue, 23 Apr 2024 19:31:35 +0800 Message-Id: <20240423113141.1752-3-xuanzhuo@linux.alibaba.com> X-Mailer: git-send-email 2.32.0.3.g01195cf9f In-Reply-To: <20240423113141.1752-1-xuanzhuo@linux.alibaba.com> References: <20240423113141.1752-1-xuanzhuo@linux.alibaba.com> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Git-Hash: 75c95ace5f2d X-Patchwork-Delegate: kuba@kernel.org The key size of ethtool -S is controlled by this macro. ETH_GSTRING_LEN 32 That includes the \0 at the end. So the max length of the key name must is 31. But the length of the prefix "rx_queue_0_" is 11. If the queue num is larger than 10, the length of the prefix is 12. So the key name max is 19. That is too short. We will introduce some keys such as "gso_packets_coalesced". So we should change the prefix to "rx0_". Signed-off-by: Xuan Zhuo Acked-by: Jason Wang --- drivers/net/virtio_net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 921b2254594f..bd90f9d3d9b7 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -3278,13 +3278,13 @@ static void virtnet_get_strings(struct net_device *dev, u32 stringset, u8 *data) case ETH_SS_STATS: for (i = 0; i < vi->curr_queue_pairs; i++) { for (j = 0; j < VIRTNET_RQ_STATS_LEN; j++) - ethtool_sprintf(&p, "rx_queue_%u_%s", i, + ethtool_sprintf(&p, "rx%u_%s", i, virtnet_rq_stats_desc[j].desc); } for (i = 0; i < vi->curr_queue_pairs; i++) { for (j = 0; j < VIRTNET_SQ_STATS_LEN; j++) - ethtool_sprintf(&p, "tx_queue_%u_%s", i, + ethtool_sprintf(&p, "tx%u_%s", i, virtnet_sq_stats_desc[j].desc); } break; From patchwork Tue Apr 23 11:31:36 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xuan Zhuo X-Patchwork-Id: 13639889 X-Patchwork-Delegate: kuba@kernel.org Received: from out30-130.freemail.mail.aliyun.com (out30-130.freemail.mail.aliyun.com [115.124.30.130]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2DA618004E; Tue, 23 Apr 2024 11:31:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.30.130 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713871914; cv=none; b=Owtl6WKJ41Zr91JY76xrYnICh/HLquNZS/D+k1bGdKzruwAJB09a//8GegGElIReIxJXBYSWxdafOy9Y0tsoqm3XIOPnfjiIo5Ddi9MAh69Opy9tSUxz6yxN3emv/p3SOMVFTfPT/0ARw/PGGYDIIxYQNkKNTAahKSNl3JTxRtE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713871914; c=relaxed/simple; bh=uIiWMYrcJifIQXHUo+DjMa00IxnJ7lWREDIAJfI9SII=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=WaM7SrVqD5yftZ5TdaTT0iBNCAMl7V9PW1lfFv8xVHLXE/Rlgf4qld+cY0x+sqeQXjt+Lh8NFCQN2GJPdvJtiVTLjjpClep/X35yBVIbnVZMQqSMHVu+j8cWn5cOZjuUotGWYg8ueR0AS/TGLJtCIoMhmYTSLI/npsH8umgF+yY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com; spf=pass smtp.mailfrom=linux.alibaba.com; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b=JbUDg+pb; arc=none smtp.client-ip=115.124.30.130 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b="JbUDg+pb" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1713871908; h=From:To:Subject:Date:Message-Id:MIME-Version; bh=V9oAS4CIshZzTfqf7tTuRNrroNwYJY0NXx6SGPJpT8o=; b=JbUDg+pbz/KrL8y+sOkMwlZLs6elTTQskXSnm4lXZ16+Pip2JHpuerrTsuafYhxnQy7dY8CBCetSXAcKW97eEiZvdGHQyckJw7QKZrs0NmSKGJWlQfqW7Rr0Z9AfUEDL5FaHoDPS7/JF/r2rlQveOI56MuzuDzU3Y15ZLIpEDCQ= X-Alimail-AntiSpam: AC=PASS;BC=-1|-1;BR=01201311R171e4;CH=green;DM=||false|;DS=||;FP=0|-1|-1|-1|0|-1|-1|-1;HT=ay29a033018045170;MF=xuanzhuo@linux.alibaba.com;NM=1;PH=DS;RN=19;SR=0;TI=SMTPD_---0W591Z7U_1713871906; Received: from localhost(mailfrom:xuanzhuo@linux.alibaba.com fp:SMTPD_---0W591Z7U_1713871906) by smtp.aliyun-inc.com; Tue, 23 Apr 2024 19:31:47 +0800 From: Xuan Zhuo To: netdev@vger.kernel.org Cc: "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , "Michael S. Tsirkin" , Jason Wang , Xuan Zhuo , Alexei Starovoitov , Daniel Borkmann , Jesper Dangaard Brouer , John Fastabend , Stanislav Fomichev , Amritha Nambiar , Larysa Zaremba , Sridhar Samudrala , Maciej Fijalkowski , virtualization@lists.linux.dev, bpf@vger.kernel.org Subject: [PATCH net-next v6 3/8] virtio_net: support device stats Date: Tue, 23 Apr 2024 19:31:36 +0800 Message-Id: <20240423113141.1752-4-xuanzhuo@linux.alibaba.com> X-Mailer: git-send-email 2.32.0.3.g01195cf9f In-Reply-To: <20240423113141.1752-1-xuanzhuo@linux.alibaba.com> References: <20240423113141.1752-1-xuanzhuo@linux.alibaba.com> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Git-Hash: 75c95ace5f2d X-Patchwork-Delegate: kuba@kernel.org As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82 make virtio-net support getting the stats from the device by ethtool -S . NIC statistics: rx0_packets: 582951 rx0_bytes: 155307077 rx0_drops: 0 rx0_xdp_packets: 0 rx0_xdp_tx: 0 rx0_xdp_redirects: 0 rx0_xdp_drops: 0 rx0_kicks: 17007 rx0_hw_packets: 2179409 rx0_hw_bytes: 510015040 rx0_hw_notifications: 0 rx0_hw_interrupts: 0 rx0_hw_needs_csum: 2179409 rx0_hw_ratelimit_bytes: 0 tx0_packets: 15361 tx0_bytes: 1918970 tx0_xdp_tx: 0 tx0_xdp_tx_drops: 0 tx0_kicks: 15361 tx0_timeouts: 0 tx0_hw_packets: 32272 tx0_hw_bytes: 4311698 tx0_hw_notifications: 0 tx0_hw_interrupts: 0 tx0_hw_ratelimit_bytes: 0 The follow stats are hidden, there are exported by the queue stat API in the subsequent comment. VIRTNET_STATS_DESC_RX(basic, drops) VIRTNET_STATS_DESC_RX(basic, drop_overruns), VIRTNET_STATS_DESC_TX(basic, drops), VIRTNET_STATS_DESC_TX(basic, drop_malformed), VIRTNET_STATS_DESC_RX(csum, csum_valid), VIRTNET_STATS_DESC_RX(csum, csum_none), VIRTNET_STATS_DESC_RX(csum, csum_bad), VIRTNET_STATS_DESC_TX(csum, needs_csum), VIRTNET_STATS_DESC_TX(csum, csum_none), VIRTNET_STATS_DESC_RX(gso, gso_packets), VIRTNET_STATS_DESC_RX(gso, gso_bytes), VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced), VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced), VIRTNET_STATS_DESC_TX(gso, gso_packets), VIRTNET_STATS_DESC_TX(gso, gso_bytes), VIRTNET_STATS_DESC_TX(gso, gso_segments), VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes), VIRTNET_STATS_DESC_RX(speed, ratelimit_packets), VIRTNET_STATS_DESC_TX(speed, ratelimit_packets), Signed-off-by: Xuan Zhuo Acked-by: Jason Wang --- drivers/net/virtio_net.c | 476 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 472 insertions(+), 4 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index bd90f9d3d9b7..acae0c310688 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -128,6 +128,57 @@ static const struct virtnet_stat_desc virtnet_rq_stats_desc[] = { #define VIRTNET_SQ_STATS_LEN ARRAY_SIZE(virtnet_sq_stats_desc) #define VIRTNET_RQ_STATS_LEN ARRAY_SIZE(virtnet_rq_stats_desc) +#define VIRTNET_STATS_DESC_CQ(name) \ + {#name, offsetof(struct virtio_net_stats_cvq, name)} + +#define VIRTNET_STATS_DESC_RX(class, name) \ + {#name, offsetof(struct virtio_net_stats_rx_ ## class, rx_ ## name)} + +#define VIRTNET_STATS_DESC_TX(class, name) \ + {#name, offsetof(struct virtio_net_stats_tx_ ## class, tx_ ## name)} + +static const struct virtnet_stat_desc virtnet_stats_cvq_desc[] = { + VIRTNET_STATS_DESC_CQ(command_num), + VIRTNET_STATS_DESC_CQ(ok_num), +}; + +static const struct virtnet_stat_desc virtnet_stats_rx_basic_desc[] = { + VIRTNET_STATS_DESC_RX(basic, packets), + VIRTNET_STATS_DESC_RX(basic, bytes), + + VIRTNET_STATS_DESC_RX(basic, notifications), + VIRTNET_STATS_DESC_RX(basic, interrupts), +}; + +static const struct virtnet_stat_desc virtnet_stats_tx_basic_desc[] = { + VIRTNET_STATS_DESC_TX(basic, packets), + VIRTNET_STATS_DESC_TX(basic, bytes), + + VIRTNET_STATS_DESC_TX(basic, notifications), + VIRTNET_STATS_DESC_TX(basic, interrupts), +}; + +static const struct virtnet_stat_desc virtnet_stats_rx_csum_desc[] = { + VIRTNET_STATS_DESC_RX(csum, needs_csum), +}; + +static const struct virtnet_stat_desc virtnet_stats_tx_gso_desc[] = { + VIRTNET_STATS_DESC_TX(gso, gso_packets_noseg), + VIRTNET_STATS_DESC_TX(gso, gso_bytes_noseg), +}; + +static const struct virtnet_stat_desc virtnet_stats_rx_speed_desc[] = { + VIRTNET_STATS_DESC_RX(speed, ratelimit_bytes), +}; + +static const struct virtnet_stat_desc virtnet_stats_tx_speed_desc[] = { + VIRTNET_STATS_DESC_TX(speed, ratelimit_bytes), +}; + +#define VIRTNET_Q_TYPE_RX 0 +#define VIRTNET_Q_TYPE_TX 1 +#define VIRTNET_Q_TYPE_CQ 2 + struct virtnet_interrupt_coalesce { u32 max_packets; u32 max_usecs; @@ -244,6 +295,7 @@ struct control_buf { struct virtio_net_ctrl_coal_tx coal_tx; struct virtio_net_ctrl_coal_rx coal_rx; struct virtio_net_ctrl_coal_vq coal_vq; + struct virtio_net_stats_capabilities stats_cap; }; struct virtnet_info { @@ -329,6 +381,8 @@ struct virtnet_info { /* failover when STANDBY feature enabled */ struct failover *failover; + + u64 device_stats_cap; }; struct padded_vnet_hdr { @@ -389,6 +443,17 @@ static int rxq2vq(int rxq) return rxq * 2; } +static int vq_type(struct virtnet_info *vi, int qid) +{ + if (qid == vi->max_queue_pairs * 2) + return VIRTNET_Q_TYPE_CQ; + + if (qid % 2) + return VIRTNET_Q_TYPE_TX; + + return VIRTNET_Q_TYPE_RX; +} + static inline struct virtio_net_common_hdr * skb_vnet_common_hdr(struct sk_buff *skb) { @@ -3268,6 +3333,369 @@ static int virtnet_set_channels(struct net_device *dev, return err; } +static void virtnet_stats_sprintf(u8 **p, const char *fmt, const char *noq_fmt, + int num, int qid, const struct virtnet_stat_desc *desc) +{ + int i; + + if (qid < 0) { + for (i = 0; i < num; ++i) + ethtool_sprintf(p, noq_fmt, desc[i].desc); + } else { + for (i = 0; i < num; ++i) + ethtool_sprintf(p, fmt, qid, desc[i].desc); + } +} + +static void virtnet_get_hw_stats_string(struct virtnet_info *vi, int type, int qid, u8 **data) +{ + const struct virtnet_stat_desc *desc; + const char *fmt, *noq_fmt; + u8 *p = *data; + u32 num = 0; + + if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_DEVICE_STATS)) + return; + + if (type == VIRTNET_Q_TYPE_CQ) { + noq_fmt = "cq_hw_%s"; + + if (VIRTIO_NET_STATS_TYPE_CVQ & vi->device_stats_cap) { + desc = &virtnet_stats_cvq_desc[0]; + num = ARRAY_SIZE(virtnet_stats_cvq_desc); + + virtnet_stats_sprintf(&p, NULL, noq_fmt, num, -1, desc); + } + } + + if (type == VIRTNET_Q_TYPE_RX) { + fmt = "rx%u_hw_%s"; + + if (VIRTIO_NET_STATS_TYPE_RX_BASIC & vi->device_stats_cap) { + desc = &virtnet_stats_rx_basic_desc[0]; + num = ARRAY_SIZE(virtnet_stats_rx_basic_desc); + + virtnet_stats_sprintf(&p, fmt, NULL, num, qid, desc); + } + + if (VIRTIO_NET_STATS_TYPE_RX_CSUM & vi->device_stats_cap) { + desc = &virtnet_stats_rx_csum_desc[0]; + num = ARRAY_SIZE(virtnet_stats_rx_csum_desc); + + virtnet_stats_sprintf(&p, fmt, NULL, num, qid, desc); + } + + if (VIRTIO_NET_STATS_TYPE_RX_SPEED & vi->device_stats_cap) { + desc = &virtnet_stats_rx_speed_desc[0]; + num = ARRAY_SIZE(virtnet_stats_rx_speed_desc); + + virtnet_stats_sprintf(&p, fmt, NULL, num, qid, desc); + } + } + + if (type == VIRTNET_Q_TYPE_TX) { + fmt = "tx%u_hw_%s"; + + if (VIRTIO_NET_STATS_TYPE_TX_BASIC & vi->device_stats_cap) { + desc = &virtnet_stats_tx_basic_desc[0]; + num = ARRAY_SIZE(virtnet_stats_tx_basic_desc); + + virtnet_stats_sprintf(&p, fmt, NULL, num, qid, desc); + } + + if (VIRTIO_NET_STATS_TYPE_TX_GSO & vi->device_stats_cap) { + desc = &virtnet_stats_tx_gso_desc[0]; + num = ARRAY_SIZE(virtnet_stats_tx_gso_desc); + + virtnet_stats_sprintf(&p, fmt, NULL, num, qid, desc); + } + + if (VIRTIO_NET_STATS_TYPE_TX_SPEED & vi->device_stats_cap) { + desc = &virtnet_stats_tx_speed_desc[0]; + num = ARRAY_SIZE(virtnet_stats_tx_speed_desc); + + virtnet_stats_sprintf(&p, fmt, NULL, num, qid, desc); + } + } + + *data = p; +} + +struct virtnet_stats_ctx { + /* Used to calculate the offset inside the output buffer. */ + u32 desc_num[3]; + + /* The actual supported stat types. */ + u32 bitmap[3]; + + /* Used to calculate the reply buffer size. */ + u32 size[3]; + + /* Record the output buffer. */ + u64 *data; +}; + +static void virtnet_stats_ctx_init(struct virtnet_info *vi, + struct virtnet_stats_ctx *ctx, + u64 *data) +{ + u32 queue_type; + + ctx->data = data; + + if (VIRTIO_NET_STATS_TYPE_CVQ & vi->device_stats_cap) { + queue_type = VIRTNET_Q_TYPE_CQ; + + ctx->bitmap[queue_type] |= VIRTIO_NET_STATS_TYPE_CVQ; + ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_cvq_desc); + ctx->size[queue_type] += sizeof(struct virtio_net_stats_cvq); + } + + queue_type = VIRTNET_Q_TYPE_RX; + + if (VIRTIO_NET_STATS_TYPE_RX_BASIC & vi->device_stats_cap) { + ctx->bitmap[queue_type] |= VIRTIO_NET_STATS_TYPE_RX_BASIC; + ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_rx_basic_desc); + ctx->size[queue_type] += sizeof(struct virtio_net_stats_rx_basic); + } + + if (VIRTIO_NET_STATS_TYPE_RX_CSUM & vi->device_stats_cap) { + ctx->bitmap[queue_type] |= VIRTIO_NET_STATS_TYPE_RX_CSUM; + ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_rx_csum_desc); + ctx->size[queue_type] += sizeof(struct virtio_net_stats_rx_csum); + } + + if (VIRTIO_NET_STATS_TYPE_RX_SPEED & vi->device_stats_cap) { + ctx->bitmap[queue_type] |= VIRTIO_NET_STATS_TYPE_RX_SPEED; + ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_rx_speed_desc); + ctx->size[queue_type] += sizeof(struct virtio_net_stats_rx_speed); + } + + queue_type = VIRTNET_Q_TYPE_TX; + + if (VIRTIO_NET_STATS_TYPE_TX_BASIC & vi->device_stats_cap) { + ctx->bitmap[queue_type] |= VIRTIO_NET_STATS_TYPE_TX_BASIC; + ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_tx_basic_desc); + ctx->size[queue_type] += sizeof(struct virtio_net_stats_tx_basic); + } + + if (VIRTIO_NET_STATS_TYPE_TX_GSO & vi->device_stats_cap) { + ctx->bitmap[queue_type] |= VIRTIO_NET_STATS_TYPE_TX_GSO; + ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_tx_gso_desc); + ctx->size[queue_type] += sizeof(struct virtio_net_stats_tx_gso); + } + + if (VIRTIO_NET_STATS_TYPE_TX_SPEED & vi->device_stats_cap) { + ctx->bitmap[queue_type] |= VIRTIO_NET_STATS_TYPE_TX_SPEED; + ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_tx_speed_desc); + ctx->size[queue_type] += sizeof(struct virtio_net_stats_tx_speed); + } +} + +/* virtnet_fill_stats - copy the stats to ethtool -S + * The stats source is the device. + * + * @vi: virtio net info + * @qid: the vq id + * @ctx: stats ctx (initiated by virtnet_stats_ctx_init()) + * @base: pointer to the device reply. + * @type: the type of the device reply + */ +static void virtnet_fill_stats(struct virtnet_info *vi, u32 qid, + struct virtnet_stats_ctx *ctx, + const u8 *base, u8 reply_type) +{ + u32 queue_type, num_rx, num_tx, num_cq; + const struct virtnet_stat_desc *desc; + u64 offset, bitmap; + const __le64 *v; + int i, num; + + num_rx = VIRTNET_RQ_STATS_LEN + ctx->desc_num[VIRTNET_Q_TYPE_RX]; + num_tx = VIRTNET_SQ_STATS_LEN + ctx->desc_num[VIRTNET_Q_TYPE_TX]; + num_cq = ctx->desc_num[VIRTNET_Q_TYPE_CQ]; + + queue_type = vq_type(vi, qid); + bitmap = ctx->bitmap[queue_type]; + offset = 0; + + if (queue_type == VIRTNET_Q_TYPE_TX) { + offset = num_cq + num_rx * vi->curr_queue_pairs + num_tx * (qid / 2); + offset += VIRTNET_SQ_STATS_LEN; + } else if (queue_type == VIRTNET_Q_TYPE_RX) { + offset = num_cq + num_rx * (qid / 2) + VIRTNET_RQ_STATS_LEN; + } + + if (VIRTIO_NET_STATS_TYPE_CVQ & bitmap) { + desc = &virtnet_stats_cvq_desc[0]; + num = ARRAY_SIZE(virtnet_stats_cvq_desc); + if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_CVQ) + goto found; + + offset += num; + } + + if (VIRTIO_NET_STATS_TYPE_RX_BASIC & bitmap) { + desc = &virtnet_stats_rx_basic_desc[0]; + num = ARRAY_SIZE(virtnet_stats_rx_basic_desc); + if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_RX_BASIC) + goto found; + + offset += num; + } + + if (VIRTIO_NET_STATS_TYPE_RX_CSUM & bitmap) { + desc = &virtnet_stats_rx_csum_desc[0]; + num = ARRAY_SIZE(virtnet_stats_rx_csum_desc); + if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_RX_CSUM) + goto found; + + offset += num; + } + + if (VIRTIO_NET_STATS_TYPE_RX_SPEED & bitmap) { + desc = &virtnet_stats_rx_speed_desc[0]; + num = ARRAY_SIZE(virtnet_stats_rx_speed_desc); + if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_RX_SPEED) + goto found; + + offset += num; + } + + if (VIRTIO_NET_STATS_TYPE_TX_BASIC & bitmap) { + desc = &virtnet_stats_tx_basic_desc[0]; + num = ARRAY_SIZE(virtnet_stats_tx_basic_desc); + if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_TX_BASIC) + goto found; + + offset += num; + } + + if (VIRTIO_NET_STATS_TYPE_TX_GSO & bitmap) { + desc = &virtnet_stats_tx_gso_desc[0]; + num = ARRAY_SIZE(virtnet_stats_tx_gso_desc); + if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_TX_GSO) + goto found; + + offset += num; + } + + if (VIRTIO_NET_STATS_TYPE_TX_SPEED & bitmap) { + desc = &virtnet_stats_tx_speed_desc[0]; + num = ARRAY_SIZE(virtnet_stats_tx_speed_desc); + if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_TX_SPEED) + goto found; + + offset += num; + } + + return; + +found: + for (i = 0; i < num; ++i) { + v = (const __le64 *)(base + desc[i].offset); + ctx->data[offset + i] = le64_to_cpu(*v); + } +} + +static int __virtnet_get_hw_stats(struct virtnet_info *vi, + struct virtnet_stats_ctx *ctx, + struct virtio_net_ctrl_queue_stats *req, + int req_size, void *reply, int res_size) +{ + struct virtio_net_stats_reply_hdr *hdr; + struct scatterlist sgs_in, sgs_out; + void *p; + u32 qid; + int ok; + + sg_init_one(&sgs_out, req, req_size); + sg_init_one(&sgs_in, reply, res_size); + + ok = virtnet_send_command_reply(vi, VIRTIO_NET_CTRL_STATS, + VIRTIO_NET_CTRL_STATS_GET, + &sgs_out, &sgs_in); + + if (!ok) + return ok; + + for (p = reply; p - reply < res_size; p += le16_to_cpu(hdr->size)) { + hdr = p; + qid = le16_to_cpu(hdr->vq_index); + virtnet_fill_stats(vi, qid, ctx, p, hdr->type); + } + + return 0; +} + +static void virtnet_make_stat_req(struct virtnet_info *vi, + struct virtnet_stats_ctx *ctx, + struct virtio_net_ctrl_queue_stats *req, + int qid, int *idx) +{ + int qtype = vq_type(vi, qid); + u64 bitmap = ctx->bitmap[qtype]; + + if (!bitmap) + return; + + req->stats[*idx].vq_index = cpu_to_le16(qid); + req->stats[*idx].types_bitmap[0] = cpu_to_le64(bitmap); + *idx += 1; +} + +static int virtnet_get_hw_stats(struct virtnet_info *vi, + struct virtnet_stats_ctx *ctx) +{ + struct virtio_net_ctrl_queue_stats *req; + int qnum, i, j, res_size, qtype, last_vq; + void *reply; + int ok; + + if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_DEVICE_STATS)) + return 0; + + last_vq = vi->curr_queue_pairs * 2 - 1; + + qnum = 0; + res_size = 0; + for (i = 0; i <= last_vq ; ++i) { + qtype = vq_type(vi, i); + if (ctx->bitmap[qtype]) { + ++qnum; + res_size += ctx->size[qtype]; + } + } + + if (ctx->bitmap[VIRTNET_Q_TYPE_CQ]) { + res_size += ctx->size[VIRTNET_Q_TYPE_CQ]; + qnum += 1; + } + + req = kcalloc(qnum, sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + reply = kmalloc(res_size, GFP_KERNEL); + if (!reply) { + kfree(req); + return -ENOMEM; + } + + j = 0; + for (i = 0; i <= last_vq ; ++i) + virtnet_make_stat_req(vi, ctx, req, i, &j); + + virtnet_make_stat_req(vi, ctx, req, vi->max_queue_pairs * 2, &j); + + ok = __virtnet_get_hw_stats(vi, ctx, req, sizeof(*req) * j, reply, res_size); + + kfree(req); + kfree(reply); + + return ok; +} + static void virtnet_get_strings(struct net_device *dev, u32 stringset, u8 *data) { struct virtnet_info *vi = netdev_priv(dev); @@ -3276,16 +3704,22 @@ static void virtnet_get_strings(struct net_device *dev, u32 stringset, u8 *data) switch (stringset) { case ETH_SS_STATS: + virtnet_get_hw_stats_string(vi, VIRTNET_Q_TYPE_CQ, 0, &p); + for (i = 0; i < vi->curr_queue_pairs; i++) { for (j = 0; j < VIRTNET_RQ_STATS_LEN; j++) ethtool_sprintf(&p, "rx%u_%s", i, virtnet_rq_stats_desc[j].desc); + + virtnet_get_hw_stats_string(vi, VIRTNET_Q_TYPE_RX, i, &p); } for (i = 0; i < vi->curr_queue_pairs; i++) { for (j = 0; j < VIRTNET_SQ_STATS_LEN; j++) ethtool_sprintf(&p, "tx%u_%s", i, virtnet_sq_stats_desc[j].desc); + + virtnet_get_hw_stats_string(vi, VIRTNET_Q_TYPE_TX, i, &p); } break; } @@ -3294,11 +3728,17 @@ static void virtnet_get_strings(struct net_device *dev, u32 stringset, u8 *data) static int virtnet_get_sset_count(struct net_device *dev, int sset) { struct virtnet_info *vi = netdev_priv(dev); + struct virtnet_stats_ctx ctx = {0}; + u32 pair_count; switch (sset) { case ETH_SS_STATS: - return vi->curr_queue_pairs * (VIRTNET_RQ_STATS_LEN + - VIRTNET_SQ_STATS_LEN); + virtnet_stats_ctx_init(vi, &ctx, NULL); + + pair_count = VIRTNET_RQ_STATS_LEN + VIRTNET_SQ_STATS_LEN; + pair_count += ctx.desc_num[VIRTNET_Q_TYPE_RX] + ctx.desc_num[VIRTNET_Q_TYPE_TX]; + + return ctx.desc_num[VIRTNET_Q_TYPE_CQ] + vi->curr_queue_pairs * pair_count; default: return -EOPNOTSUPP; } @@ -3308,11 +3748,18 @@ static void virtnet_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) { struct virtnet_info *vi = netdev_priv(dev); - unsigned int idx = 0, start, i, j; + struct virtnet_stats_ctx ctx = {0}; + unsigned int idx, start, i, j; const u8 *stats_base; const u64_stats_t *p; size_t offset; + virtnet_stats_ctx_init(vi, &ctx, data); + if (virtnet_get_hw_stats(vi, &ctx)) + dev_warn(&vi->dev->dev, "Failed to get hw stats.\n"); + + idx = ctx.desc_num[VIRTNET_Q_TYPE_CQ]; + for (i = 0; i < vi->curr_queue_pairs; i++) { struct receive_queue *rq = &vi->rq[i]; @@ -3326,6 +3773,7 @@ static void virtnet_get_ethtool_stats(struct net_device *dev, } } while (u64_stats_fetch_retry(&rq->stats.syncp, start)); idx += VIRTNET_RQ_STATS_LEN; + idx += ctx.desc_num[VIRTNET_Q_TYPE_RX]; } for (i = 0; i < vi->curr_queue_pairs; i++) { @@ -3341,6 +3789,7 @@ static void virtnet_get_ethtool_stats(struct net_device *dev, } } while (u64_stats_fetch_retry(&sq->stats.syncp, start)); idx += VIRTNET_SQ_STATS_LEN; + idx += ctx.desc_num[VIRTNET_Q_TYPE_TX]; } } @@ -4840,6 +5289,25 @@ static int virtnet_probe(struct virtio_device *vdev) } } + if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_DEVICE_STATS)) { + struct scatterlist sg; + __le64 v; + + sg_init_one(&sg, &vi->ctrl->stats_cap, sizeof(vi->ctrl->stats_cap)); + + if (!virtnet_send_command_reply(vi, VIRTIO_NET_CTRL_STATS, + VIRTIO_NET_CTRL_STATS_QUERY, + NULL, &sg)) { + pr_debug("virtio_net: fail to get stats capability\n"); + rtnl_unlock(); + err = -EINVAL; + goto free_unregister_netdev; + } + + v = vi->ctrl->stats_cap.supported_stats_types[0]; + vi->device_stats_cap = le64_to_cpu(v); + } + rtnl_unlock(); err = virtnet_cpu_notif_add(vi); @@ -4966,7 +5434,7 @@ static struct virtio_device_id id_table[] = { VIRTIO_NET_F_SPEED_DUPLEX, VIRTIO_NET_F_STANDBY, \ VIRTIO_NET_F_RSS, VIRTIO_NET_F_HASH_REPORT, VIRTIO_NET_F_NOTF_COAL, \ VIRTIO_NET_F_VQ_NOTF_COAL, \ - VIRTIO_NET_F_GUEST_HDRLEN + VIRTIO_NET_F_GUEST_HDRLEN, VIRTIO_NET_F_DEVICE_STATS static unsigned int features[] = { VIRTNET_FEATURES, From patchwork Tue Apr 23 11:31:37 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xuan Zhuo X-Patchwork-Id: 13639892 X-Patchwork-Delegate: kuba@kernel.org Received: from out30-110.freemail.mail.aliyun.com (out30-110.freemail.mail.aliyun.com [115.124.30.110]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C806785278; Tue, 23 Apr 2024 11:31:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.30.110 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713871920; cv=none; b=uBNkrulVVbxLj+aSFpZzbfVFWnVD0vx6smYUK3X95SQWSiJmaEl4JxauEaahK7xRgGcRHciwAZIxDJHeLIoq/ODUNxppTXddPmjShVa3sm2oMa2MUM/0lAiaXnvRbeUdrlNFEEd7SGbZIuVwlDkDoyimuBxG8NIHAjjDkctiSCk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713871920; c=relaxed/simple; bh=EXTPP5AuAXTCkLO19qrRysI5zs1pn4K1SI570o/82eQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Ll9PelMkQ2ufNtBsyh/iCd5oR5QxNGVJHzMhpRMFRH1IdzuGJi/wKqT5QthFaKL1dfaupiTyvitMPto0vBngUTm5v396TzAr+3vEnra0TvZIXfWi6/2xCL+P9tsGrGooyD+BOXvg4VimD7l0F+OuJkVCMoBz3rbq9bat/H2MmJ0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com; spf=pass smtp.mailfrom=linux.alibaba.com; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b=JGTg3cwD; arc=none smtp.client-ip=115.124.30.110 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b="JGTg3cwD" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1713871910; h=From:To:Subject:Date:Message-Id:MIME-Version; bh=IZFppeLH1d3MqL5PBllcng/AyoH22MqfCAkun1ouuWI=; b=JGTg3cwDNZDY53xZwt7Q2xTHtyTwXkW4h/yZ5eEE6LGAqWfUm1Iq1N+4ORVIKVXy7K7q3V6l72AY1qGGYDrYn5R72K/rezl5GAtvtgKqdG3r0O82jE5TMRHe87RJm933+9VPJ7VkUNJxszcO2n81m/VFOwRJ+E3L0yQHsGGxC8E= X-Alimail-AntiSpam: AC=PASS;BC=-1|-1;BR=01201311R121e4;CH=green;DM=||false|;DS=||;FP=0|-1|-1|-1|0|-1|-1|-1;HT=ay29a033018046060;MF=xuanzhuo@linux.alibaba.com;NM=1;PH=DS;RN=19;SR=0;TI=SMTPD_---0W591Z8X_1713871907; Received: from localhost(mailfrom:xuanzhuo@linux.alibaba.com fp:SMTPD_---0W591Z8X_1713871907) by smtp.aliyun-inc.com; Tue, 23 Apr 2024 19:31:48 +0800 From: Xuan Zhuo To: netdev@vger.kernel.org Cc: "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , "Michael S. Tsirkin" , Jason Wang , Xuan Zhuo , Alexei Starovoitov , Daniel Borkmann , Jesper Dangaard Brouer , John Fastabend , Stanislav Fomichev , Amritha Nambiar , Larysa Zaremba , Sridhar Samudrala , Maciej Fijalkowski , virtualization@lists.linux.dev, bpf@vger.kernel.org Subject: [PATCH net-next v6 4/8] virtio_net: device stats helpers support driver stats Date: Tue, 23 Apr 2024 19:31:37 +0800 Message-Id: <20240423113141.1752-5-xuanzhuo@linux.alibaba.com> X-Mailer: git-send-email 2.32.0.3.g01195cf9f In-Reply-To: <20240423113141.1752-1-xuanzhuo@linux.alibaba.com> References: <20240423113141.1752-1-xuanzhuo@linux.alibaba.com> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Git-Hash: 75c95ace5f2d X-Patchwork-Delegate: kuba@kernel.org In the last commit, we introduced some helpers for device stats. And the drivers stats are realized by the open code. This commit make the helpers to support driver stats. Then we can have the unify helper for device and driver stats. Signed-off-by: Xuan Zhuo Acked-by: Jason Wang --- drivers/net/virtio_net.c | 157 ++++++++++++++++++++------------------- 1 file changed, 82 insertions(+), 75 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index acae0c310688..6d24cd8fb15f 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -102,32 +102,29 @@ struct virtnet_rq_stats { u64_stats_t kicks; }; -#define VIRTNET_SQ_STAT(m) offsetof(struct virtnet_sq_stats, m) -#define VIRTNET_RQ_STAT(m) offsetof(struct virtnet_rq_stats, m) +#define VIRTNET_SQ_STAT(name, m) {name, offsetof(struct virtnet_sq_stats, m)} +#define VIRTNET_RQ_STAT(name, m) {name, offsetof(struct virtnet_rq_stats, m)} static const struct virtnet_stat_desc virtnet_sq_stats_desc[] = { - { "packets", VIRTNET_SQ_STAT(packets) }, - { "bytes", VIRTNET_SQ_STAT(bytes) }, - { "xdp_tx", VIRTNET_SQ_STAT(xdp_tx) }, - { "xdp_tx_drops", VIRTNET_SQ_STAT(xdp_tx_drops) }, - { "kicks", VIRTNET_SQ_STAT(kicks) }, - { "tx_timeouts", VIRTNET_SQ_STAT(tx_timeouts) }, + VIRTNET_SQ_STAT("packets", packets), + VIRTNET_SQ_STAT("bytes", bytes), + VIRTNET_SQ_STAT("xdp_tx", xdp_tx), + VIRTNET_SQ_STAT("xdp_tx_drops", xdp_tx_drops), + VIRTNET_SQ_STAT("kicks", kicks), + VIRTNET_SQ_STAT("tx_timeouts", tx_timeouts), }; static const struct virtnet_stat_desc virtnet_rq_stats_desc[] = { - { "packets", VIRTNET_RQ_STAT(packets) }, - { "bytes", VIRTNET_RQ_STAT(bytes) }, - { "drops", VIRTNET_RQ_STAT(drops) }, - { "xdp_packets", VIRTNET_RQ_STAT(xdp_packets) }, - { "xdp_tx", VIRTNET_RQ_STAT(xdp_tx) }, - { "xdp_redirects", VIRTNET_RQ_STAT(xdp_redirects) }, - { "xdp_drops", VIRTNET_RQ_STAT(xdp_drops) }, - { "kicks", VIRTNET_RQ_STAT(kicks) }, + VIRTNET_RQ_STAT("packets", packets), + VIRTNET_RQ_STAT("bytes", bytes), + VIRTNET_RQ_STAT("drops", drops), + VIRTNET_RQ_STAT("xdp_packets", xdp_packets), + VIRTNET_RQ_STAT("xdp_tx", xdp_tx), + VIRTNET_RQ_STAT("xdp_redirects", xdp_redirects), + VIRTNET_RQ_STAT("xdp_drops", xdp_drops), + VIRTNET_RQ_STAT("kicks", kicks), }; -#define VIRTNET_SQ_STATS_LEN ARRAY_SIZE(virtnet_sq_stats_desc) -#define VIRTNET_RQ_STATS_LEN ARRAY_SIZE(virtnet_rq_stats_desc) - #define VIRTNET_STATS_DESC_CQ(name) \ {#name, offsetof(struct virtio_net_stats_cvq, name)} @@ -2194,7 +2191,7 @@ static int virtnet_receive(struct receive_queue *rq, int budget, u64_stats_set(&stats.packets, packets); u64_stats_update_begin(&rq->stats.syncp); - for (i = 0; i < VIRTNET_RQ_STATS_LEN; i++) { + for (i = 0; i < ARRAY_SIZE(virtnet_rq_stats_desc); i++) { size_t offset = virtnet_rq_stats_desc[i].offset; u64_stats_t *item, *src; @@ -3347,16 +3344,13 @@ static void virtnet_stats_sprintf(u8 **p, const char *fmt, const char *noq_fmt, } } -static void virtnet_get_hw_stats_string(struct virtnet_info *vi, int type, int qid, u8 **data) +static void virtnet_get_stats_string(struct virtnet_info *vi, int type, int qid, u8 **data) { const struct virtnet_stat_desc *desc; const char *fmt, *noq_fmt; u8 *p = *data; u32 num = 0; - if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_DEVICE_STATS)) - return; - if (type == VIRTNET_Q_TYPE_CQ) { noq_fmt = "cq_hw_%s"; @@ -3369,6 +3363,13 @@ static void virtnet_get_hw_stats_string(struct virtnet_info *vi, int type, int q } if (type == VIRTNET_Q_TYPE_RX) { + fmt = "rx%u_%s"; + + desc = &virtnet_rq_stats_desc[0]; + num = ARRAY_SIZE(virtnet_rq_stats_desc); + + virtnet_stats_sprintf(&p, fmt, NULL, num, qid, desc); + fmt = "rx%u_hw_%s"; if (VIRTIO_NET_STATS_TYPE_RX_BASIC & vi->device_stats_cap) { @@ -3394,6 +3395,13 @@ static void virtnet_get_hw_stats_string(struct virtnet_info *vi, int type, int q } if (type == VIRTNET_Q_TYPE_TX) { + fmt = "tx%u_%s"; + + desc = &virtnet_sq_stats_desc[0]; + num = ARRAY_SIZE(virtnet_sq_stats_desc); + + virtnet_stats_sprintf(&p, fmt, NULL, num, qid, desc); + fmt = "tx%u_hw_%s"; if (VIRTIO_NET_STATS_TYPE_TX_BASIC & vi->device_stats_cap) { @@ -3443,6 +3451,9 @@ static void virtnet_stats_ctx_init(struct virtnet_info *vi, ctx->data = data; + ctx->desc_num[VIRTNET_Q_TYPE_RX] = ARRAY_SIZE(virtnet_rq_stats_desc); + ctx->desc_num[VIRTNET_Q_TYPE_TX] = ARRAY_SIZE(virtnet_sq_stats_desc); + if (VIRTIO_NET_STATS_TYPE_CVQ & vi->device_stats_cap) { queue_type = VIRTNET_Q_TYPE_CQ; @@ -3493,37 +3504,55 @@ static void virtnet_stats_ctx_init(struct virtnet_info *vi, } /* virtnet_fill_stats - copy the stats to ethtool -S - * The stats source is the device. + * The stats source is the device or the driver. * * @vi: virtio net info * @qid: the vq id * @ctx: stats ctx (initiated by virtnet_stats_ctx_init()) - * @base: pointer to the device reply. - * @type: the type of the device reply + * @base: pointer to the device reply or the driver stats structure. + * @drv_stats: designate the base type (device reply, driver stats) + * @type: the type of the device reply (if drv_stats is true, this must be zero) */ static void virtnet_fill_stats(struct virtnet_info *vi, u32 qid, struct virtnet_stats_ctx *ctx, - const u8 *base, u8 reply_type) + const u8 *base, bool drv_stats, u8 reply_type) { u32 queue_type, num_rx, num_tx, num_cq; const struct virtnet_stat_desc *desc; + const u64_stats_t *v_stat; u64 offset, bitmap; const __le64 *v; int i, num; - num_rx = VIRTNET_RQ_STATS_LEN + ctx->desc_num[VIRTNET_Q_TYPE_RX]; - num_tx = VIRTNET_SQ_STATS_LEN + ctx->desc_num[VIRTNET_Q_TYPE_TX]; num_cq = ctx->desc_num[VIRTNET_Q_TYPE_CQ]; + num_rx = ctx->desc_num[VIRTNET_Q_TYPE_RX]; + num_tx = ctx->desc_num[VIRTNET_Q_TYPE_TX]; queue_type = vq_type(vi, qid); bitmap = ctx->bitmap[queue_type]; offset = 0; if (queue_type == VIRTNET_Q_TYPE_TX) { - offset = num_cq + num_rx * vi->curr_queue_pairs + num_tx * (qid / 2); - offset += VIRTNET_SQ_STATS_LEN; + offset += num_cq + num_rx * vi->curr_queue_pairs + num_tx * (qid / 2); + + num = ARRAY_SIZE(virtnet_sq_stats_desc); + if (drv_stats) { + desc = &virtnet_sq_stats_desc[0]; + goto drv_stats; + } + + offset += num; + } else if (queue_type == VIRTNET_Q_TYPE_RX) { - offset = num_cq + num_rx * (qid / 2) + VIRTNET_RQ_STATS_LEN; + offset += num_cq + num_rx * (qid / 2); + + num = ARRAY_SIZE(virtnet_rq_stats_desc); + if (drv_stats) { + desc = &virtnet_rq_stats_desc[0]; + goto drv_stats; + } + + offset += num; } if (VIRTIO_NET_STATS_TYPE_CVQ & bitmap) { @@ -3596,6 +3625,14 @@ static void virtnet_fill_stats(struct virtnet_info *vi, u32 qid, v = (const __le64 *)(base + desc[i].offset); ctx->data[offset + i] = le64_to_cpu(*v); } + + return; + +drv_stats: + for (i = 0; i < num; ++i) { + v_stat = (const u64_stats_t *)(base + desc[i].offset); + ctx->data[offset + i] = u64_stats_read(v_stat); + } } static int __virtnet_get_hw_stats(struct virtnet_info *vi, @@ -3622,7 +3659,7 @@ static int __virtnet_get_hw_stats(struct virtnet_info *vi, for (p = reply; p - reply < res_size; p += le16_to_cpu(hdr->size)) { hdr = p; qid = le16_to_cpu(hdr->vq_index); - virtnet_fill_stats(vi, qid, ctx, p, hdr->type); + virtnet_fill_stats(vi, qid, ctx, p, false, hdr->type); } return 0; @@ -3699,28 +3736,18 @@ static int virtnet_get_hw_stats(struct virtnet_info *vi, static void virtnet_get_strings(struct net_device *dev, u32 stringset, u8 *data) { struct virtnet_info *vi = netdev_priv(dev); - unsigned int i, j; + unsigned int i; u8 *p = data; switch (stringset) { case ETH_SS_STATS: - virtnet_get_hw_stats_string(vi, VIRTNET_Q_TYPE_CQ, 0, &p); - - for (i = 0; i < vi->curr_queue_pairs; i++) { - for (j = 0; j < VIRTNET_RQ_STATS_LEN; j++) - ethtool_sprintf(&p, "rx%u_%s", i, - virtnet_rq_stats_desc[j].desc); + virtnet_get_stats_string(vi, VIRTNET_Q_TYPE_CQ, 0, &p); - virtnet_get_hw_stats_string(vi, VIRTNET_Q_TYPE_RX, i, &p); - } + for (i = 0; i < vi->curr_queue_pairs; ++i) + virtnet_get_stats_string(vi, VIRTNET_Q_TYPE_RX, i, &p); - for (i = 0; i < vi->curr_queue_pairs; i++) { - for (j = 0; j < VIRTNET_SQ_STATS_LEN; j++) - ethtool_sprintf(&p, "tx%u_%s", i, - virtnet_sq_stats_desc[j].desc); - - virtnet_get_hw_stats_string(vi, VIRTNET_Q_TYPE_TX, i, &p); - } + for (i = 0; i < vi->curr_queue_pairs; ++i) + virtnet_get_stats_string(vi, VIRTNET_Q_TYPE_TX, i, &p); break; } } @@ -3735,8 +3762,7 @@ static int virtnet_get_sset_count(struct net_device *dev, int sset) case ETH_SS_STATS: virtnet_stats_ctx_init(vi, &ctx, NULL); - pair_count = VIRTNET_RQ_STATS_LEN + VIRTNET_SQ_STATS_LEN; - pair_count += ctx.desc_num[VIRTNET_Q_TYPE_RX] + ctx.desc_num[VIRTNET_Q_TYPE_TX]; + pair_count = ctx.desc_num[VIRTNET_Q_TYPE_RX] + ctx.desc_num[VIRTNET_Q_TYPE_TX]; return ctx.desc_num[VIRTNET_Q_TYPE_CQ] + vi->curr_queue_pairs * pair_count; default: @@ -3749,47 +3775,28 @@ static void virtnet_get_ethtool_stats(struct net_device *dev, { struct virtnet_info *vi = netdev_priv(dev); struct virtnet_stats_ctx ctx = {0}; - unsigned int idx, start, i, j; + unsigned int start, i; const u8 *stats_base; - const u64_stats_t *p; - size_t offset; virtnet_stats_ctx_init(vi, &ctx, data); if (virtnet_get_hw_stats(vi, &ctx)) dev_warn(&vi->dev->dev, "Failed to get hw stats.\n"); - idx = ctx.desc_num[VIRTNET_Q_TYPE_CQ]; - for (i = 0; i < vi->curr_queue_pairs; i++) { struct receive_queue *rq = &vi->rq[i]; + struct send_queue *sq = &vi->sq[i]; stats_base = (const u8 *)&rq->stats; do { start = u64_stats_fetch_begin(&rq->stats.syncp); - for (j = 0; j < VIRTNET_RQ_STATS_LEN; j++) { - offset = virtnet_rq_stats_desc[j].offset; - p = (const u64_stats_t *)(stats_base + offset); - data[idx + j] = u64_stats_read(p); - } + virtnet_fill_stats(vi, i * 2, &ctx, stats_base, true, 0); } while (u64_stats_fetch_retry(&rq->stats.syncp, start)); - idx += VIRTNET_RQ_STATS_LEN; - idx += ctx.desc_num[VIRTNET_Q_TYPE_RX]; - } - - for (i = 0; i < vi->curr_queue_pairs; i++) { - struct send_queue *sq = &vi->sq[i]; stats_base = (const u8 *)&sq->stats; do { start = u64_stats_fetch_begin(&sq->stats.syncp); - for (j = 0; j < VIRTNET_SQ_STATS_LEN; j++) { - offset = virtnet_sq_stats_desc[j].offset; - p = (const u64_stats_t *)(stats_base + offset); - data[idx + j] = u64_stats_read(p); - } + virtnet_fill_stats(vi, i * 2 + 1, &ctx, stats_base, true, 0); } while (u64_stats_fetch_retry(&sq->stats.syncp, start)); - idx += VIRTNET_SQ_STATS_LEN; - idx += ctx.desc_num[VIRTNET_Q_TYPE_TX]; } } From patchwork Tue Apr 23 11:31:38 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xuan Zhuo X-Patchwork-Id: 13639890 X-Patchwork-Delegate: kuba@kernel.org Received: from out30-100.freemail.mail.aliyun.com (out30-100.freemail.mail.aliyun.com [115.124.30.100]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5235384039; Tue, 23 Apr 2024 11:31:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.30.100 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713871916; cv=none; b=ODXrPpbtfWuslgUb71vaBSBHkx0KCSZBuc0ag5kt0V/lKm3lZosOwLNN4DDQDG3wSzKpLzBBKZIj96k/GxLfNZEOkIt0GV+MIB+wsOusB6YviflGO/P2bOBlS3zhs+w6BUMPlnrh+5Pw1b6EwtS6W9oeT9ZpSbLGujbXLmy0Ih0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713871916; c=relaxed/simple; bh=fs9mBfnUo5VUwoC49M1oKhjXjQYzloflCrFTocr6Ktc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=fZqAf+0lvrh40JbfVsU5BmqnM6ou8IilA1grodw4RsHw0NaVn9HSI6nmsYCyJbCrRekCYm/tsvdMDJ2iDZjxCnbF+NNxhgNkptJFMQuKqc3ATvTgLE+F6sl0gxHqHTHTl522Bacu7bc7ya+H9Io51QBbljms0VMoS5qcvnrmWew= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com; spf=pass smtp.mailfrom=linux.alibaba.com; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b=fUrBtGLU; arc=none smtp.client-ip=115.124.30.100 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b="fUrBtGLU" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1713871912; h=From:To:Subject:Date:Message-Id:MIME-Version; bh=TRD9x7KsHx7J1Ivp7O94hlWIwg6juNJcB2vUf7rdXAU=; b=fUrBtGLUvMUXcFpzlpw7Kt276fhqUQUg3ZFtmYCd+Lyo2HN5gY8lGIu+hxmcd6uIIDBMS6Jdx6soKswgJmGsvNKykr6+O1jyWf0pdW+J0gRDt2Eq5ChqKRtYpG/NX/nZFvPCeV5vfVUNY0ImxOFFItm1Gq/J4itaxV7HsizdoE8= X-Alimail-AntiSpam: AC=PASS;BC=-1|-1;BR=01201311R221e4;CH=green;DM=||false|;DS=||;FP=0|-1|-1|-1|0|-1|-1|-1;HT=maildocker-contentspam033068173054;MF=xuanzhuo@linux.alibaba.com;NM=1;PH=DS;RN=19;SR=0;TI=SMTPD_---0W592gRd_1713871909; Received: from localhost(mailfrom:xuanzhuo@linux.alibaba.com fp:SMTPD_---0W592gRd_1713871909) by smtp.aliyun-inc.com; Tue, 23 Apr 2024 19:31:50 +0800 From: Xuan Zhuo To: netdev@vger.kernel.org Cc: "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , "Michael S. Tsirkin" , Jason Wang , Xuan Zhuo , Alexei Starovoitov , Daniel Borkmann , Jesper Dangaard Brouer , John Fastabend , Stanislav Fomichev , Amritha Nambiar , Larysa Zaremba , Sridhar Samudrala , Maciej Fijalkowski , virtualization@lists.linux.dev, bpf@vger.kernel.org Subject: [PATCH net-next v6 5/8] virtio_net: add the total stats field Date: Tue, 23 Apr 2024 19:31:38 +0800 Message-Id: <20240423113141.1752-6-xuanzhuo@linux.alibaba.com> X-Mailer: git-send-email 2.32.0.3.g01195cf9f In-Reply-To: <20240423113141.1752-1-xuanzhuo@linux.alibaba.com> References: <20240423113141.1752-1-xuanzhuo@linux.alibaba.com> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Git-Hash: 75c95ace5f2d X-Patchwork-Delegate: kuba@kernel.org Now, we just show the stats of every queue. But for the user, the total values of every stat may are valuable. NIC statistics: rx_packets: 373522 rx_bytes: 85919736 rx_drops: 0 rx_xdp_packets: 0 rx_xdp_tx: 0 rx_xdp_redirects: 0 rx_xdp_drops: 0 rx_kicks: 11125 rx_hw_notifications: 0 rx_hw_packets: 1325870 rx_hw_bytes: 263348963 rx_hw_interrupts: 0 rx_hw_drops: 1451 rx_hw_drop_overruns: 0 rx_hw_csum_valid: 1325870 rx_hw_needs_csum: 1325870 rx_hw_csum_none: 0 rx_hw_csum_bad: 0 rx_hw_ratelimit_packets: 0 rx_hw_ratelimit_bytes: 0 tx_packets: 10050 tx_bytes: 1230176 tx_xdp_tx: 0 tx_xdp_tx_drops: 0 tx_kicks: 10050 tx_timeouts: 0 tx_hw_notifications: 0 tx_hw_packets: 32281 tx_hw_bytes: 4315590 tx_hw_interrupts: 0 tx_hw_drops: 0 tx_hw_drop_malformed: 0 tx_hw_csum_none: 0 tx_hw_needs_csum: 32281 tx_hw_ratelimit_packets: 0 tx_hw_ratelimit_bytes: 0 rx0_packets: 373522 rx0_bytes: 85919736 rx0_drops: 0 rx0_xdp_packets: 0 rx0_xdp_tx: 0 rx0_xdp_redirects: 0 rx0_xdp_drops: 0 rx0_kicks: 11125 rx0_hw_notifications: 0 rx0_hw_packets: 1325870 rx0_hw_bytes: 263348963 rx0_hw_interrupts: 0 rx0_hw_drops: 1451 rx0_hw_drop_overruns: 0 rx0_hw_csum_valid: 1325870 rx0_hw_needs_csum: 1325870 rx0_hw_csum_none: 0 rx0_hw_csum_bad: 0 rx0_hw_ratelimit_packets: 0 rx0_hw_ratelimit_bytes: 0 tx0_packets: 10050 tx0_bytes: 1230176 tx0_xdp_tx: 0 tx0_xdp_tx_drops: 0 tx0_kicks: 10050 tx0_timeouts: 0 tx0_hw_notifications: 0 tx0_hw_packets: 32281 tx0_hw_bytes: 4315590 tx0_hw_interrupts: 0 tx0_hw_drops: 0 tx0_hw_drop_malformed: 0 tx0_hw_csum_none: 0 tx0_hw_needs_csum: 32281 tx0_hw_ratelimit_packets: 0 tx0_hw_ratelimit_bytes: 0 Signed-off-by: Xuan Zhuo --- drivers/net/virtio_net.c | 81 ++++++++++++++++++++++++++++++++++------ 1 file changed, 69 insertions(+), 12 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 6d24cd8fb15f..8a4d22f5f5b1 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -3344,14 +3344,15 @@ static void virtnet_stats_sprintf(u8 **p, const char *fmt, const char *noq_fmt, } } +/* qid == -1: for rx/tx queue total field */ static void virtnet_get_stats_string(struct virtnet_info *vi, int type, int qid, u8 **data) { const struct virtnet_stat_desc *desc; const char *fmt, *noq_fmt; u8 *p = *data; - u32 num = 0; + u32 num; - if (type == VIRTNET_Q_TYPE_CQ) { + if (type == VIRTNET_Q_TYPE_CQ && qid >= 0) { noq_fmt = "cq_hw_%s"; if (VIRTIO_NET_STATS_TYPE_CVQ & vi->device_stats_cap) { @@ -3364,65 +3365,69 @@ static void virtnet_get_stats_string(struct virtnet_info *vi, int type, int qid, if (type == VIRTNET_Q_TYPE_RX) { fmt = "rx%u_%s"; + noq_fmt = "rx_%s"; desc = &virtnet_rq_stats_desc[0]; num = ARRAY_SIZE(virtnet_rq_stats_desc); - virtnet_stats_sprintf(&p, fmt, NULL, num, qid, desc); + virtnet_stats_sprintf(&p, fmt, noq_fmt, num, qid, desc); fmt = "rx%u_hw_%s"; + noq_fmt = "rx_hw_%s"; if (VIRTIO_NET_STATS_TYPE_RX_BASIC & vi->device_stats_cap) { desc = &virtnet_stats_rx_basic_desc[0]; num = ARRAY_SIZE(virtnet_stats_rx_basic_desc); - virtnet_stats_sprintf(&p, fmt, NULL, num, qid, desc); + virtnet_stats_sprintf(&p, fmt, noq_fmt, num, qid, desc); } if (VIRTIO_NET_STATS_TYPE_RX_CSUM & vi->device_stats_cap) { desc = &virtnet_stats_rx_csum_desc[0]; num = ARRAY_SIZE(virtnet_stats_rx_csum_desc); - virtnet_stats_sprintf(&p, fmt, NULL, num, qid, desc); + virtnet_stats_sprintf(&p, fmt, noq_fmt, num, qid, desc); } if (VIRTIO_NET_STATS_TYPE_RX_SPEED & vi->device_stats_cap) { desc = &virtnet_stats_rx_speed_desc[0]; num = ARRAY_SIZE(virtnet_stats_rx_speed_desc); - virtnet_stats_sprintf(&p, fmt, NULL, num, qid, desc); + virtnet_stats_sprintf(&p, fmt, noq_fmt, num, qid, desc); } } if (type == VIRTNET_Q_TYPE_TX) { fmt = "tx%u_%s"; + noq_fmt = "tx_%s"; desc = &virtnet_sq_stats_desc[0]; num = ARRAY_SIZE(virtnet_sq_stats_desc); - virtnet_stats_sprintf(&p, fmt, NULL, num, qid, desc); + virtnet_stats_sprintf(&p, fmt, noq_fmt, num, qid, desc); fmt = "tx%u_hw_%s"; + noq_fmt = "tx_hw_%s"; if (VIRTIO_NET_STATS_TYPE_TX_BASIC & vi->device_stats_cap) { desc = &virtnet_stats_tx_basic_desc[0]; num = ARRAY_SIZE(virtnet_stats_tx_basic_desc); - virtnet_stats_sprintf(&p, fmt, NULL, num, qid, desc); + virtnet_stats_sprintf(&p, fmt, noq_fmt, num, qid, desc); } if (VIRTIO_NET_STATS_TYPE_TX_GSO & vi->device_stats_cap) { desc = &virtnet_stats_tx_gso_desc[0]; num = ARRAY_SIZE(virtnet_stats_tx_gso_desc); - virtnet_stats_sprintf(&p, fmt, NULL, num, qid, desc); + virtnet_stats_sprintf(&p, fmt, noq_fmt, num, qid, desc); } if (VIRTIO_NET_STATS_TYPE_TX_SPEED & vi->device_stats_cap) { desc = &virtnet_stats_tx_speed_desc[0]; num = ARRAY_SIZE(virtnet_stats_tx_speed_desc); - virtnet_stats_sprintf(&p, fmt, NULL, num, qid, desc); + virtnet_stats_sprintf(&p, fmt, noq_fmt, num, qid, desc); } } @@ -3503,6 +3508,49 @@ static void virtnet_stats_ctx_init(struct virtnet_info *vi, } } +/* stats_sum_queue - Calculate the sum of the same fields in sq or rq. + * @sum: the position to store the sum values + * @num: field num + * @q_value: the first queue fields + * @q_num: number of the queues + */ +static void stats_sum_queue(u64 *sum, u32 num, u64 *q_value, u32 q_num) +{ + u32 step = num; + int i, j; + u64 *p; + + for (i = 0; i < num; ++i) { + p = sum + i; + *p = 0; + + for (j = 0; j < q_num; ++j) + *p += *(q_value + i + j * step); + } +} + +static void virtnet_fill_total_fields(struct virtnet_info *vi, + struct virtnet_stats_ctx *ctx) +{ + u64 *data, *first_rx_q, *first_tx_q; + u32 num_cq, num_rx, num_tx; + + num_cq = ctx->desc_num[VIRTNET_Q_TYPE_CQ]; + num_rx = ctx->desc_num[VIRTNET_Q_TYPE_RX]; + num_tx = ctx->desc_num[VIRTNET_Q_TYPE_TX]; + + first_rx_q = ctx->data + num_rx + num_tx + num_cq; + first_tx_q = first_rx_q + vi->curr_queue_pairs * num_rx; + + data = ctx->data; + + stats_sum_queue(data, num_rx, first_rx_q, vi->curr_queue_pairs); + + data = ctx->data + num_rx; + + stats_sum_queue(data, num_tx, first_tx_q, vi->curr_queue_pairs); +} + /* virtnet_fill_stats - copy the stats to ethtool -S * The stats source is the device or the driver. * @@ -3530,7 +3578,9 @@ static void virtnet_fill_stats(struct virtnet_info *vi, u32 qid, queue_type = vq_type(vi, qid); bitmap = ctx->bitmap[queue_type]; - offset = 0; + + /* skip the total fields of pairs */ + offset = num_rx + num_tx; if (queue_type == VIRTNET_Q_TYPE_TX) { offset += num_cq + num_rx * vi->curr_queue_pairs + num_tx * (qid / 2); @@ -3741,6 +3791,10 @@ static void virtnet_get_strings(struct net_device *dev, u32 stringset, u8 *data) switch (stringset) { case ETH_SS_STATS: + /* Generate the total field names. */ + virtnet_get_stats_string(vi, VIRTNET_Q_TYPE_RX, -1, &p); + virtnet_get_stats_string(vi, VIRTNET_Q_TYPE_TX, -1, &p); + virtnet_get_stats_string(vi, VIRTNET_Q_TYPE_CQ, 0, &p); for (i = 0; i < vi->curr_queue_pairs; ++i) @@ -3764,7 +3818,8 @@ static int virtnet_get_sset_count(struct net_device *dev, int sset) pair_count = ctx.desc_num[VIRTNET_Q_TYPE_RX] + ctx.desc_num[VIRTNET_Q_TYPE_TX]; - return ctx.desc_num[VIRTNET_Q_TYPE_CQ] + vi->curr_queue_pairs * pair_count; + return pair_count + ctx.desc_num[VIRTNET_Q_TYPE_CQ] + + vi->curr_queue_pairs * pair_count; default: return -EOPNOTSUPP; } @@ -3798,6 +3853,8 @@ static void virtnet_get_ethtool_stats(struct net_device *dev, virtnet_fill_stats(vi, i * 2 + 1, &ctx, stats_base, true, 0); } while (u64_stats_fetch_retry(&sq->stats.syncp, start)); } + + virtnet_fill_total_fields(vi, &ctx); } static void virtnet_get_channels(struct net_device *dev, From patchwork Tue Apr 23 11:31:39 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xuan Zhuo X-Patchwork-Id: 13639894 X-Patchwork-Delegate: kuba@kernel.org Received: from out30-132.freemail.mail.aliyun.com (out30-132.freemail.mail.aliyun.com [115.124.30.132]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D347285935; Tue, 23 Apr 2024 11:32:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.30.132 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713871924; cv=none; b=QwHDeyYlbIpsllFSUK6HQueF+PHNAp+xsCSoSRg+95f172XMlNtjH/0hVO9LghzNhE3mPIqqSdU008l1lXmXsBzPcd84zzUpr4E182SOPFRenaOv/1gxSViKi09oxknWqa/osOjbas+UAu/hVDVHWt2K4DlXMlUiJWDxW9mkGSw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713871924; c=relaxed/simple; bh=jWC62fYV+ZTF5Fvowh93EkbOaVU7iP1h7ukt4bOLETs=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=HSziBoMZoK9vnIAVZdRYgApWzvq60Tvw7zhmNwi82CsPM7sTN8j4Y8zdtobhwI3HGlJcYgydXoxq0tOZo5ZE7ROKmEbieT6Ilh6nu6u0VU7kKxdMjo5ZctP9fai/eW/xPhUEb19Gwlz7QXmHDN1P9CON2ecXqCn4KrWCLyFMl7U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com; spf=pass smtp.mailfrom=linux.alibaba.com; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b=vt1hEGQ+; arc=none smtp.client-ip=115.124.30.132 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b="vt1hEGQ+" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1713871914; h=From:To:Subject:Date:Message-Id:MIME-Version; bh=b6216Qqmhhv5PtdUjYLEcywMguoHZfNZiQFsGWmMQII=; b=vt1hEGQ+Y2q30PRp3gDh5m/6AwRXzlvMyt3vROHLNCJbfBtXl4ENv5691AgHLmvCiynr4nRTcujUr4Ls2W+aV2kIg48cPmZTRHWXXmMitlkcG0AlS6qIXKIMoK3vfet8kXMSy9mbKAbcQ0Y2dqEK2dThMgjAE1b5pfbe2P0rJiA= X-Alimail-AntiSpam: AC=PASS;BC=-1|-1;BR=01201311R421e4;CH=green;DM=||false|;DS=||;FP=0|-1|-1|-1|0|-1|-1|-1;HT=ay29a033018046050;MF=xuanzhuo@linux.alibaba.com;NM=1;PH=DS;RN=20;SR=0;TI=SMTPD_---0W591ZAE_1713871911; Received: from localhost(mailfrom:xuanzhuo@linux.alibaba.com fp:SMTPD_---0W591ZAE_1713871911) by smtp.aliyun-inc.com; Tue, 23 Apr 2024 19:31:52 +0800 From: Xuan Zhuo To: netdev@vger.kernel.org Cc: "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , "Michael S. Tsirkin" , Jason Wang , Xuan Zhuo , Alexei Starovoitov , Daniel Borkmann , Jesper Dangaard Brouer , John Fastabend , Stanislav Fomichev , Amritha Nambiar , Larysa Zaremba , Sridhar Samudrala , Maciej Fijalkowski , virtualization@lists.linux.dev, bpf@vger.kernel.org, Jiri Pirko Subject: [PATCH net-next v6 6/8] virtio_net: rename stat tx_timeout to timeout Date: Tue, 23 Apr 2024 19:31:39 +0800 Message-Id: <20240423113141.1752-7-xuanzhuo@linux.alibaba.com> X-Mailer: git-send-email 2.32.0.3.g01195cf9f In-Reply-To: <20240423113141.1752-1-xuanzhuo@linux.alibaba.com> References: <20240423113141.1752-1-xuanzhuo@linux.alibaba.com> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Git-Hash: 75c95ace5f2d X-Patchwork-Delegate: kuba@kernel.org Now, we have this: tx_queue_0_tx_timeouts This is used to record the tx schedule timeout. But this has two "tx". I think the below is enough. tx_queue_0_timeouts So I rename this field. Signed-off-by: Xuan Zhuo Reviewed-by: Jiri Pirko --- drivers/net/virtio_net.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 8a4d22f5f5b1..51ce2308f4f5 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -87,7 +87,7 @@ struct virtnet_sq_stats { u64_stats_t xdp_tx; u64_stats_t xdp_tx_drops; u64_stats_t kicks; - u64_stats_t tx_timeouts; + u64_stats_t timeouts; }; struct virtnet_rq_stats { @@ -111,7 +111,7 @@ static const struct virtnet_stat_desc virtnet_sq_stats_desc[] = { VIRTNET_SQ_STAT("xdp_tx", xdp_tx), VIRTNET_SQ_STAT("xdp_tx_drops", xdp_tx_drops), VIRTNET_SQ_STAT("kicks", kicks), - VIRTNET_SQ_STAT("tx_timeouts", tx_timeouts), + VIRTNET_SQ_STAT("timeouts", timeouts), }; static const struct virtnet_stat_desc virtnet_rq_stats_desc[] = { @@ -2691,7 +2691,7 @@ static void virtnet_stats(struct net_device *dev, start = u64_stats_fetch_begin(&sq->stats.syncp); tpackets = u64_stats_read(&sq->stats.packets); tbytes = u64_stats_read(&sq->stats.bytes); - terrors = u64_stats_read(&sq->stats.tx_timeouts); + terrors = u64_stats_read(&sq->stats.timeouts); } while (u64_stats_fetch_retry(&sq->stats.syncp, start)); do { @@ -4639,7 +4639,7 @@ static void virtnet_tx_timeout(struct net_device *dev, unsigned int txqueue) struct netdev_queue *txq = netdev_get_tx_queue(dev, txqueue); u64_stats_update_begin(&sq->stats.syncp); - u64_stats_inc(&sq->stats.tx_timeouts); + u64_stats_inc(&sq->stats.timeouts); u64_stats_update_end(&sq->stats.syncp); netdev_err(dev, "TX timeout on queue: %u, sq: %s, vq: 0x%x, name: %s, %u usecs ago\n", From patchwork Tue Apr 23 11:31:40 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xuan Zhuo X-Patchwork-Id: 13639895 X-Patchwork-Delegate: kuba@kernel.org Received: from out30-132.freemail.mail.aliyun.com (out30-132.freemail.mail.aliyun.com [115.124.30.132]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BE86C8563D; Tue, 23 Apr 2024 11:32:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.30.132 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713871925; cv=none; b=WdrJhwxghkpdDcqvpvqd3LAE8SG16TkYONaVvmOp0ntx3FTS7doCOrvXpDIIn5chBqsO1WqZajWYs5IZ0aoVZnsvowZ+006OOeo1CBKxvv67upreDzwoD/uFAhS6y2+pDGaUCBRMNUoy1HL7P460dbdJy+k3352IHhTRC4fdX0g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713871925; c=relaxed/simple; bh=7Mr/4ivr3Y/mLeJHyrMzIgpQgY7W1JKx1wFWQ8Z1leU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=L3ajjYPBMW0oO0DZDI59cZ503VOllSd6QkSwPXdq3NWcJSltS5+QGxW/MUQ0bYVif+445KJCtX96PVJBYj1rPldgfo0sx5Q6LZEpfniN1IZ+1lI2cVopjhBvxl3Q9rSYZjDZjih5uxwMy16HFo9GBi89rTYDt78Um3csssR2qtI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com; spf=pass smtp.mailfrom=linux.alibaba.com; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b=VZlumKBG; arc=none smtp.client-ip=115.124.30.132 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b="VZlumKBG" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1713871915; h=From:To:Subject:Date:Message-Id:MIME-Version; bh=G2ylAct8v28rDflvY+HwznLPnqQmZx6wEikbnF/lZBY=; b=VZlumKBGGxkMmkcSytrtFlgUgW2FRKy6yYJk4bXtd4TguiWYBJNirjVPX0MwIcR7Yv7IId32ddlvyrWOHlBY3eAQIlla8zPIqv9A91g7kcshAMcHKrfZU+/SiaDgRmZg7/vfEpvXARmhceEiKX4qfoBc7nRjkmWOGBw2HFNItxw= X-Alimail-AntiSpam: AC=PASS;BC=-1|-1;BR=01201311R211e4;CH=green;DM=||false|;DS=||;FP=0|-1|-1|-1|0|-1|-1|-1;HT=maildocker-contentspam033068173054;MF=xuanzhuo@linux.alibaba.com;NM=1;PH=DS;RN=19;SR=0;TI=SMTPD_---0W592gT._1713871912; Received: from localhost(mailfrom:xuanzhuo@linux.alibaba.com fp:SMTPD_---0W592gT._1713871912) by smtp.aliyun-inc.com; Tue, 23 Apr 2024 19:31:53 +0800 From: Xuan Zhuo To: netdev@vger.kernel.org Cc: "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , "Michael S. Tsirkin" , Jason Wang , Xuan Zhuo , Alexei Starovoitov , Daniel Borkmann , Jesper Dangaard Brouer , John Fastabend , Stanislav Fomichev , Amritha Nambiar , Larysa Zaremba , Sridhar Samudrala , Maciej Fijalkowski , virtualization@lists.linux.dev, bpf@vger.kernel.org Subject: [PATCH net-next v6 7/8] netdev: add queue stats Date: Tue, 23 Apr 2024 19:31:40 +0800 Message-Id: <20240423113141.1752-8-xuanzhuo@linux.alibaba.com> X-Mailer: git-send-email 2.32.0.3.g01195cf9f In-Reply-To: <20240423113141.1752-1-xuanzhuo@linux.alibaba.com> References: <20240423113141.1752-1-xuanzhuo@linux.alibaba.com> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Git-Hash: 75c95ace5f2d X-Patchwork-Delegate: kuba@kernel.org These stats are commonly. Support reporting those via netdev-genl queue stats. name: rx-hw-drops name: rx-hw-drop-overruns name: rx-csum-unnecessary name: rx-csum-none name: rx-csum-bad name: rx-hw-gro-packets name: rx-hw-gro-bytes name: rx-hw-gro-wire-packets name: rx-hw-gro-wire-bytes name: rx-hw-drop-ratelimits name: tx-hw-drops name: tx-hw-drop-errors name: tx-csum-none name: tx-needs-csum name: tx-hw-gso-packets name: tx-hw-gso-bytes name: tx-hw-gso-wire-packets name: tx-hw-gso-wire-bytes name: tx-hw-drop-ratelimits Signed-off-by: Xuan Zhuo --- Documentation/netlink/specs/netdev.yaml | 104 ++++++++++++++++++++++++ include/net/netdev_queues.h | 27 ++++++ include/uapi/linux/netdev.h | 19 +++++ net/core/netdev-genl.c | 23 +++++- tools/include/uapi/linux/netdev.h | 19 +++++ 5 files changed, 190 insertions(+), 2 deletions(-) diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml index 76352dbd2be4..31b51b60ef13 100644 --- a/Documentation/netlink/specs/netdev.yaml +++ b/Documentation/netlink/specs/netdev.yaml @@ -335,6 +335,110 @@ attribute-sets: Allocation failure may, or may not result in a packet drop, depending on driver implementation and whether system recovers quickly. type: uint + - + name: rx-hw-drops + doc: | + Number of all packets which entered the device, but never left it, + including but not limited to: packets dropped due to lack of buffer + space, processing errors, explicit or implicit policies and packet + filters. + type: uint + - + name: rx-hw-drop-overruns + doc: | + Number of packets dropped due to transient lack of resources, such as + buffer space, host descriptors etc. + type: uint + - + name: rx-csum-unnecessary + doc: Number of packets that were marked as CHECKSUM_UNNECESSARY. + type: uint + - + name: rx-csum-none + doc: Number of packets that were not checksummed by device. + type: uint + - + name: rx-csum-bad + doc: | + Number of packets with bad checksum. The packets are not discarded, + but still delivered to the stack. + type: uint + - + name: rx-hw-gro-packets + doc: | + Number of packets that were coalesced from smaller packets by the device. + Counts only packets coalesced with the HW-GRO netdevice feature, + LRO-coalesced packets are not counted. + type: uint + - + name: rx-hw-gro-bytes + doc: See `rx-hw-gro-packets`. + type: uint + - + name: rx-hw-gro-wire-packets + doc: | + Number of packets that were coalesced to bigger packetss with the HW-GRO + netdevice feature. LRO-coalesced packets are not counted. + type: uint + - + name: rx-hw-gro-wire-bytes + doc: See `rx-hw-gro-wire-packets`. + type: uint + - + name: rx-hw-drop-ratelimits + doc: | + Number of the packets dropped by the device due to the received + packets bitrate exceeding the device rate limit. + type: uint + - + name: tx-hw-drops + doc: | + Number of packets that arrived at the device but never left it, + encompassing packets dropped for reasons such as processing errors, as + well as those affected by explicitly defined policies and packet + filtering criteria. + type: uint + - + name: tx-hw-drop-errors + doc: Number of packets dropped because they were invalid or malformed. + type: uint + - + name: tx-csum-none + doc: | + Number of packets that did not require the device to calculate the + checksum. + type: uint + - + name: tx-needs-csum + doc: | + Number of packets that required the device to calculate the checksum. + type: uint + - + name: tx-hw-gso-packets + doc: | + Number of packets that necessitated segmentation into smaller packets + by the device. + type: uint + - + name: tx-hw-gso-bytes + doc: See `tx-hw-gso-packets`. + type: uint + - + name: tx-hw-gso-wire-packets + doc: | + Number of wire-sized packets generated by processing + `tx-hw-gso-packets` + type: uint + - + name: tx-hw-gso-wire-bytes + doc: See `tx-hw-gso-wire-packets`. + type: uint + - + name: tx-hw-drop-ratelimits + doc: | + Number of the packets dropped by the device due to the transmit + packets bitrate exceeding the device rate limit. + type: uint operations: list: diff --git a/include/net/netdev_queues.h b/include/net/netdev_queues.h index 1ec408585373..c7ac4539eafc 100644 --- a/include/net/netdev_queues.h +++ b/include/net/netdev_queues.h @@ -9,11 +9,38 @@ struct netdev_queue_stats_rx { u64 bytes; u64 packets; u64 alloc_fail; + + u64 hw_drops; + u64 hw_drop_overruns; + + u64 csum_unnecessary; + u64 csum_none; + u64 csum_bad; + + u64 hw_gro_packets; + u64 hw_gro_bytes; + u64 hw_gro_wire_packets; + u64 hw_gro_wire_bytes; + + u64 hw_drop_ratelimits; }; struct netdev_queue_stats_tx { u64 bytes; u64 packets; + + u64 hw_drops; + u64 hw_drop_errors; + + u64 csum_none; + u64 needs_csum; + + u64 hw_gso_packets; + u64 hw_gso_bytes; + u64 hw_gso_wire_packets; + u64 hw_gso_wire_bytes; + + u64 hw_drop_ratelimits; }; /** diff --git a/include/uapi/linux/netdev.h b/include/uapi/linux/netdev.h index bb65ee840cda..cf24f1d9adf8 100644 --- a/include/uapi/linux/netdev.h +++ b/include/uapi/linux/netdev.h @@ -146,6 +146,25 @@ enum { NETDEV_A_QSTATS_TX_PACKETS, NETDEV_A_QSTATS_TX_BYTES, NETDEV_A_QSTATS_RX_ALLOC_FAIL, + NETDEV_A_QSTATS_RX_HW_DROPS, + NETDEV_A_QSTATS_RX_HW_DROP_OVERRUNS, + NETDEV_A_QSTATS_RX_CSUM_UNNECESSARY, + NETDEV_A_QSTATS_RX_CSUM_NONE, + NETDEV_A_QSTATS_RX_CSUM_BAD, + NETDEV_A_QSTATS_RX_HW_GRO_PACKETS, + NETDEV_A_QSTATS_RX_HW_GRO_BYTES, + NETDEV_A_QSTATS_RX_HW_GRO_WIRE_PACKETS, + NETDEV_A_QSTATS_RX_HW_GRO_WIRE_BYTES, + NETDEV_A_QSTATS_RX_HW_DROP_RATELIMITS, + NETDEV_A_QSTATS_TX_HW_DROPS, + NETDEV_A_QSTATS_TX_HW_DROP_ERRORS, + NETDEV_A_QSTATS_TX_CSUM_NONE, + NETDEV_A_QSTATS_TX_NEEDS_CSUM, + NETDEV_A_QSTATS_TX_HW_GSO_PACKETS, + NETDEV_A_QSTATS_TX_HW_GSO_BYTES, + NETDEV_A_QSTATS_TX_HW_GSO_WIRE_PACKETS, + NETDEV_A_QSTATS_TX_HW_GSO_WIRE_BYTES, + NETDEV_A_QSTATS_TX_HW_DROP_RATELIMITS, __NETDEV_A_QSTATS_MAX, NETDEV_A_QSTATS_MAX = (__NETDEV_A_QSTATS_MAX - 1) diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c index 7004b3399c2b..a2bf9af2dcf6 100644 --- a/net/core/netdev-genl.c +++ b/net/core/netdev-genl.c @@ -489,7 +489,17 @@ netdev_nl_stats_write_rx(struct sk_buff *rsp, struct netdev_queue_stats_rx *rx) { if (netdev_stat_put(rsp, NETDEV_A_QSTATS_RX_PACKETS, rx->packets) || netdev_stat_put(rsp, NETDEV_A_QSTATS_RX_BYTES, rx->bytes) || - netdev_stat_put(rsp, NETDEV_A_QSTATS_RX_ALLOC_FAIL, rx->alloc_fail)) + netdev_stat_put(rsp, NETDEV_A_QSTATS_RX_ALLOC_FAIL, rx->alloc_fail) || + netdev_stat_put(rsp, NETDEV_A_QSTATS_RX_HW_DROPS, rx->hw_drops) || + netdev_stat_put(rsp, NETDEV_A_QSTATS_RX_HW_DROP_OVERRUNS, rx->hw_drop_overruns) || + netdev_stat_put(rsp, NETDEV_A_QSTATS_RX_CSUM_UNNECESSARY, rx->csum_unnecessary) || + netdev_stat_put(rsp, NETDEV_A_QSTATS_RX_CSUM_NONE, rx->csum_none) || + netdev_stat_put(rsp, NETDEV_A_QSTATS_RX_CSUM_BAD, rx->csum_bad) || + netdev_stat_put(rsp, NETDEV_A_QSTATS_RX_HW_GRO_PACKETS, rx->hw_gro_packets) || + netdev_stat_put(rsp, NETDEV_A_QSTATS_RX_HW_GRO_BYTES, rx->hw_gro_bytes) || + netdev_stat_put(rsp, NETDEV_A_QSTATS_RX_HW_GRO_WIRE_PACKETS, rx->hw_gro_wire_packets) || + netdev_stat_put(rsp, NETDEV_A_QSTATS_RX_HW_GRO_WIRE_BYTES, rx->hw_gro_wire_bytes) || + netdev_stat_put(rsp, NETDEV_A_QSTATS_RX_HW_DROP_RATELIMITS, rx->hw_drop_ratelimits)) return -EMSGSIZE; return 0; } @@ -498,7 +508,16 @@ static int netdev_nl_stats_write_tx(struct sk_buff *rsp, struct netdev_queue_stats_tx *tx) { if (netdev_stat_put(rsp, NETDEV_A_QSTATS_TX_PACKETS, tx->packets) || - netdev_stat_put(rsp, NETDEV_A_QSTATS_TX_BYTES, tx->bytes)) + netdev_stat_put(rsp, NETDEV_A_QSTATS_TX_BYTES, tx->bytes) || + netdev_stat_put(rsp, NETDEV_A_QSTATS_TX_HW_DROPS, tx->hw_drops) || + netdev_stat_put(rsp, NETDEV_A_QSTATS_TX_HW_DROP_ERRORS, tx->hw_drop_errors) || + netdev_stat_put(rsp, NETDEV_A_QSTATS_TX_CSUM_NONE, tx->csum_none) || + netdev_stat_put(rsp, NETDEV_A_QSTATS_TX_NEEDS_CSUM, tx->needs_csum) || + netdev_stat_put(rsp, NETDEV_A_QSTATS_TX_HW_GSO_PACKETS, tx->hw_gso_packets) || + netdev_stat_put(rsp, NETDEV_A_QSTATS_TX_HW_GSO_BYTES, tx->hw_gso_bytes) || + netdev_stat_put(rsp, NETDEV_A_QSTATS_TX_HW_GSO_WIRE_PACKETS, tx->hw_gso_wire_packets) || + netdev_stat_put(rsp, NETDEV_A_QSTATS_TX_HW_GSO_WIRE_BYTES, tx->hw_gso_wire_bytes) || + netdev_stat_put(rsp, NETDEV_A_QSTATS_TX_HW_DROP_RATELIMITS, tx->hw_drop_ratelimits)) return -EMSGSIZE; return 0; } diff --git a/tools/include/uapi/linux/netdev.h b/tools/include/uapi/linux/netdev.h index bb65ee840cda..cf24f1d9adf8 100644 --- a/tools/include/uapi/linux/netdev.h +++ b/tools/include/uapi/linux/netdev.h @@ -146,6 +146,25 @@ enum { NETDEV_A_QSTATS_TX_PACKETS, NETDEV_A_QSTATS_TX_BYTES, NETDEV_A_QSTATS_RX_ALLOC_FAIL, + NETDEV_A_QSTATS_RX_HW_DROPS, + NETDEV_A_QSTATS_RX_HW_DROP_OVERRUNS, + NETDEV_A_QSTATS_RX_CSUM_UNNECESSARY, + NETDEV_A_QSTATS_RX_CSUM_NONE, + NETDEV_A_QSTATS_RX_CSUM_BAD, + NETDEV_A_QSTATS_RX_HW_GRO_PACKETS, + NETDEV_A_QSTATS_RX_HW_GRO_BYTES, + NETDEV_A_QSTATS_RX_HW_GRO_WIRE_PACKETS, + NETDEV_A_QSTATS_RX_HW_GRO_WIRE_BYTES, + NETDEV_A_QSTATS_RX_HW_DROP_RATELIMITS, + NETDEV_A_QSTATS_TX_HW_DROPS, + NETDEV_A_QSTATS_TX_HW_DROP_ERRORS, + NETDEV_A_QSTATS_TX_CSUM_NONE, + NETDEV_A_QSTATS_TX_NEEDS_CSUM, + NETDEV_A_QSTATS_TX_HW_GSO_PACKETS, + NETDEV_A_QSTATS_TX_HW_GSO_BYTES, + NETDEV_A_QSTATS_TX_HW_GSO_WIRE_PACKETS, + NETDEV_A_QSTATS_TX_HW_GSO_WIRE_BYTES, + NETDEV_A_QSTATS_TX_HW_DROP_RATELIMITS, __NETDEV_A_QSTATS_MAX, NETDEV_A_QSTATS_MAX = (__NETDEV_A_QSTATS_MAX - 1) From patchwork Tue Apr 23 11:31:41 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xuan Zhuo X-Patchwork-Id: 13639893 X-Patchwork-Delegate: kuba@kernel.org Received: from out30-118.freemail.mail.aliyun.com (out30-118.freemail.mail.aliyun.com [115.124.30.118]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CF1F285287; Tue, 23 Apr 2024 11:31:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.30.118 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713871921; cv=none; b=ZBbB6kHzLEzhY6YU8ggrAbSZ5ZJ00ciNNpHI0T7b1joQ6qf+AQPk/fVKSqpSOHkQs4bvRmGk3MAtOHP1wA0WY4btmR5qBvFfk+MQQ+G431GoT0i3hyCbybYkZxbf9f09UMJ68KHjCdqAvvB/I97rvJU0ECxDAsgE3tUQywBusKg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713871921; c=relaxed/simple; bh=1jtpcWgjoCh73JvlWjZiAJuPjO4+9ruY5D3Z66Qefz0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=X/aiIE/HmvW8AaggUABmeu6joSPblBaAuA0hmeB3bcTRs8Elzc5sInvlP7idcrwa5M4AsiNSBFXca3d377yKA/h71N0SCKFE2HT3YmEvYQrM3MIRpuE337tlW43rNJQFckheWf7+QWevvREFSRIQx+GvpOgFAF+23j16vpHTWOU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com; spf=pass smtp.mailfrom=linux.alibaba.com; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b=MwU8eysK; arc=none smtp.client-ip=115.124.30.118 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b="MwU8eysK" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1713871916; h=From:To:Subject:Date:Message-Id:MIME-Version; bh=OxkOzBk9LeDfb7JH999d2oC0hw5ai5ZleQXXWY4x2zc=; b=MwU8eysKkoN7AWzJVVAbj1/w3DGEZ77d5sZAigLYqdOnHtrdqm/McLbYCNh3nYP6ff6sQI5w6RKtOJjl1nX2WLmZ5Q6EpAbfEG6R5SjTwsWzV01/Q2QJUFrOcxrprhVWrp4M5ItzGHxrA4xNZizaEPSnsHZ89wHrXyH5Lw8/ntw= X-Alimail-AntiSpam: AC=PASS;BC=-1|-1;BR=01201311R101e4;CH=green;DM=||false|;DS=||;FP=0|-1|-1|-1|0|-1|-1|-1;HT=maildocker-contentspam033037067110;MF=xuanzhuo@linux.alibaba.com;NM=1;PH=DS;RN=19;SR=0;TI=SMTPD_---0W591ZBw_1713871914; Received: from localhost(mailfrom:xuanzhuo@linux.alibaba.com fp:SMTPD_---0W591ZBw_1713871914) by smtp.aliyun-inc.com; Tue, 23 Apr 2024 19:31:55 +0800 From: Xuan Zhuo To: netdev@vger.kernel.org Cc: "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , "Michael S. Tsirkin" , Jason Wang , Xuan Zhuo , Alexei Starovoitov , Daniel Borkmann , Jesper Dangaard Brouer , John Fastabend , Stanislav Fomichev , Amritha Nambiar , Larysa Zaremba , Sridhar Samudrala , Maciej Fijalkowski , virtualization@lists.linux.dev, bpf@vger.kernel.org Subject: [PATCH net-next v6 8/8] virtio-net: support queue stat Date: Tue, 23 Apr 2024 19:31:41 +0800 Message-Id: <20240423113141.1752-9-xuanzhuo@linux.alibaba.com> X-Mailer: git-send-email 2.32.0.3.g01195cf9f In-Reply-To: <20240423113141.1752-1-xuanzhuo@linux.alibaba.com> References: <20240423113141.1752-1-xuanzhuo@linux.alibaba.com> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Git-Hash: 75c95ace5f2d X-Patchwork-Delegate: kuba@kernel.org To enhance functionality, we now support reporting statistics through the netdev-generic netlink (netdev-genl) queue stats interface. However, this does not extend to all statistics, so a new field, qstat_offset, has been introduced. This field determines which statistics should be reported via netdev-genl queue stats. Given that queue stats are retrieved individually per queue, it's necessary for the virtnet_get_hw_stats() function to be capable of fetching statistics for a specific queue. As the document https://docs.kernel.org/next/networking/statistics.html#notes-for-driver-authors We should not duplicate the stats which get reported via the netlink API in ethtool. If the stats are for queue stat, that will not be reported by ethtool -S. python3 ./tools/net/ynl/cli.py --spec Documentation/netlink/specs/netdev.yaml --dump qstats-get --json '{"scope": "queue"}' [{'ifindex': 2, 'queue-id': 0, 'queue-type': 'rx', 'rx-bytes': 157844011, 'rx-csum-bad': 0, 'rx-csum-none': 0, 'rx-csum-unnecessary': 2195386, 'rx-hw-drop-overruns': 0, 'rx-hw-drop-ratelimits': 0, 'rx-hw-drops': 12964, 'rx-packets': 598929}, {'ifindex': 2, 'queue-id': 0, 'queue-type': 'tx', 'tx-bytes': 1938511, 'tx-csum-none': 0, 'tx-hw-drop-errors': 0, 'tx-hw-drop-ratelimits': 0, 'tx-hw-drops': 0, 'tx-needs-csum': 61263, 'tx-packets': 15515}] Signed-off-by: Xuan Zhuo --- drivers/net/virtio_net.c | 369 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 348 insertions(+), 21 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 51ce2308f4f5..446a44a5cad9 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -24,6 +24,7 @@ #include #include #include +#include static int napi_weight = NAPI_POLL_WEIGHT; module_param(napi_weight, int, 0444); @@ -78,6 +79,7 @@ static const unsigned long guest_offloads[] = { struct virtnet_stat_desc { char desc[ETH_GSTRING_LEN]; size_t offset; + size_t qstat_offset; }; struct virtnet_sq_stats { @@ -102,12 +104,24 @@ struct virtnet_rq_stats { u64_stats_t kicks; }; -#define VIRTNET_SQ_STAT(name, m) {name, offsetof(struct virtnet_sq_stats, m)} -#define VIRTNET_RQ_STAT(name, m) {name, offsetof(struct virtnet_rq_stats, m)} +#define VIRTNET_SQ_STAT(name, m) {name, offsetof(struct virtnet_sq_stats, m), -1} +#define VIRTNET_RQ_STAT(name, m) {name, offsetof(struct virtnet_rq_stats, m), -1} + +#define VIRTNET_SQ_STAT_QSTAT(name, m) \ + { \ + name, \ + offsetof(struct virtnet_sq_stats, m), \ + offsetof(struct netdev_queue_stats_tx, m), \ + } + +#define VIRTNET_RQ_STAT_QSTAT(name, m) \ + { \ + name, \ + offsetof(struct virtnet_rq_stats, m), \ + offsetof(struct netdev_queue_stats_rx, m), \ + } static const struct virtnet_stat_desc virtnet_sq_stats_desc[] = { - VIRTNET_SQ_STAT("packets", packets), - VIRTNET_SQ_STAT("bytes", bytes), VIRTNET_SQ_STAT("xdp_tx", xdp_tx), VIRTNET_SQ_STAT("xdp_tx_drops", xdp_tx_drops), VIRTNET_SQ_STAT("kicks", kicks), @@ -115,8 +129,6 @@ static const struct virtnet_stat_desc virtnet_sq_stats_desc[] = { }; static const struct virtnet_stat_desc virtnet_rq_stats_desc[] = { - VIRTNET_RQ_STAT("packets", packets), - VIRTNET_RQ_STAT("bytes", bytes), VIRTNET_RQ_STAT("drops", drops), VIRTNET_RQ_STAT("xdp_packets", xdp_packets), VIRTNET_RQ_STAT("xdp_tx", xdp_tx), @@ -125,14 +137,25 @@ static const struct virtnet_stat_desc virtnet_rq_stats_desc[] = { VIRTNET_RQ_STAT("kicks", kicks), }; +static const struct virtnet_stat_desc virtnet_sq_stats_desc_qstat[] = { + VIRTNET_SQ_STAT_QSTAT("packets", packets), + VIRTNET_SQ_STAT_QSTAT("bytes", bytes), +}; + +static const struct virtnet_stat_desc virtnet_rq_stats_desc_qstat[] = { + VIRTNET_RQ_STAT_QSTAT("packets", packets), + VIRTNET_RQ_STAT_QSTAT("bytes", bytes), +}; + #define VIRTNET_STATS_DESC_CQ(name) \ - {#name, offsetof(struct virtio_net_stats_cvq, name)} + {#name, offsetof(struct virtio_net_stats_cvq, name), -1} #define VIRTNET_STATS_DESC_RX(class, name) \ - {#name, offsetof(struct virtio_net_stats_rx_ ## class, rx_ ## name)} + {#name, offsetof(struct virtio_net_stats_rx_ ## class, rx_ ## name), -1} #define VIRTNET_STATS_DESC_TX(class, name) \ - {#name, offsetof(struct virtio_net_stats_tx_ ## class, tx_ ## name)} + {#name, offsetof(struct virtio_net_stats_tx_ ## class, tx_ ## name), -1} + static const struct virtnet_stat_desc virtnet_stats_cvq_desc[] = { VIRTNET_STATS_DESC_CQ(command_num), @@ -172,6 +195,63 @@ static const struct virtnet_stat_desc virtnet_stats_tx_speed_desc[] = { VIRTNET_STATS_DESC_TX(speed, ratelimit_bytes), }; +#define VIRTNET_STATS_DESC_RX_QSTAT(class, name, qstat_field) \ + { \ + #name, \ + offsetof(struct virtio_net_stats_rx_ ## class, rx_ ## name), \ + offsetof(struct netdev_queue_stats_rx, qstat_field), \ + } + +#define VIRTNET_STATS_DESC_TX_QSTAT(class, name, qstat_field) \ + { \ + #name, \ + offsetof(struct virtio_net_stats_tx_ ## class, tx_ ## name), \ + offsetof(struct netdev_queue_stats_tx, qstat_field), \ + } + +static const struct virtnet_stat_desc virtnet_stats_rx_basic_desc_qstat[] = { + VIRTNET_STATS_DESC_RX_QSTAT(basic, drops, hw_drops), + VIRTNET_STATS_DESC_RX_QSTAT(basic, drop_overruns, hw_drop_overruns), +}; + +static const struct virtnet_stat_desc virtnet_stats_tx_basic_desc_qstat[] = { + VIRTNET_STATS_DESC_TX_QSTAT(basic, drops, hw_drops), + VIRTNET_STATS_DESC_TX_QSTAT(basic, drop_malformed, hw_drop_errors), +}; + +static const struct virtnet_stat_desc virtnet_stats_rx_csum_desc_qstat[] = { + VIRTNET_STATS_DESC_RX_QSTAT(csum, csum_valid, csum_unnecessary), + VIRTNET_STATS_DESC_RX_QSTAT(csum, csum_none, csum_none), + VIRTNET_STATS_DESC_RX_QSTAT(csum, csum_bad, csum_bad), +}; + +static const struct virtnet_stat_desc virtnet_stats_tx_csum_desc_qstat[] = { + VIRTNET_STATS_DESC_TX_QSTAT(csum, csum_none, csum_none), + VIRTNET_STATS_DESC_TX_QSTAT(csum, needs_csum, needs_csum), +}; + +static const struct virtnet_stat_desc virtnet_stats_rx_gso_desc_qstat[] = { + VIRTNET_STATS_DESC_RX_QSTAT(gso, gso_packets, hw_gro_packets), + VIRTNET_STATS_DESC_RX_QSTAT(gso, gso_bytes, hw_gro_bytes), + VIRTNET_STATS_DESC_RX_QSTAT(gso, gso_packets_coalesced, hw_gro_wire_packets), + VIRTNET_STATS_DESC_RX_QSTAT(gso, gso_bytes_coalesced, hw_gro_wire_bytes), +}; + +static const struct virtnet_stat_desc virtnet_stats_tx_gso_desc_qstat[] = { + VIRTNET_STATS_DESC_TX_QSTAT(gso, gso_packets, hw_gso_packets), + VIRTNET_STATS_DESC_TX_QSTAT(gso, gso_bytes, hw_gso_bytes), + VIRTNET_STATS_DESC_TX_QSTAT(gso, gso_segments, hw_gso_wire_packets), + VIRTNET_STATS_DESC_TX_QSTAT(gso, gso_segments_bytes, hw_gso_wire_bytes), +}; + +static const struct virtnet_stat_desc virtnet_stats_rx_speed_desc_qstat[] = { + VIRTNET_STATS_DESC_RX_QSTAT(speed, ratelimit_packets, hw_drop_ratelimits), +}; + +static const struct virtnet_stat_desc virtnet_stats_tx_speed_desc_qstat[] = { + VIRTNET_STATS_DESC_TX_QSTAT(speed, ratelimit_packets, hw_drop_ratelimits), +}; + #define VIRTNET_Q_TYPE_RX 0 #define VIRTNET_Q_TYPE_TX 1 #define VIRTNET_Q_TYPE_CQ 2 @@ -2199,6 +2279,10 @@ static int virtnet_receive(struct receive_queue *rq, int budget, src = (u64_stats_t *)((u8 *)&stats + offset); u64_stats_add(item, u64_stats_read(src)); } + + u64_stats_add(&rq->stats.packets, u64_stats_read(&stats.packets)); + u64_stats_add(&rq->stats.bytes, u64_stats_read(&stats.bytes)); + u64_stats_update_end(&rq->stats.syncp); return packets; @@ -3435,6 +3519,9 @@ static void virtnet_get_stats_string(struct virtnet_info *vi, int type, int qid, } struct virtnet_stats_ctx { + /* The stats are write to qstats or ethtool -S */ + bool to_qstat; + /* Used to calculate the offset inside the output buffer. */ u32 desc_num[3]; @@ -3450,11 +3537,71 @@ struct virtnet_stats_ctx { static void virtnet_stats_ctx_init(struct virtnet_info *vi, struct virtnet_stats_ctx *ctx, - u64 *data) + u64 *data, bool to_qstat) { u32 queue_type; ctx->data = data; + ctx->to_qstat = to_qstat; + + if (to_qstat) { + ctx->desc_num[VIRTNET_Q_TYPE_RX] = ARRAY_SIZE(virtnet_rq_stats_desc_qstat); + ctx->desc_num[VIRTNET_Q_TYPE_TX] = ARRAY_SIZE(virtnet_sq_stats_desc_qstat); + + queue_type = VIRTNET_Q_TYPE_RX; + + if (VIRTIO_NET_STATS_TYPE_RX_BASIC & vi->device_stats_cap) { + ctx->bitmap[queue_type] |= VIRTIO_NET_STATS_TYPE_RX_BASIC; + ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_rx_basic_desc_qstat); + ctx->size[queue_type] += sizeof(struct virtio_net_stats_rx_basic); + } + + if (VIRTIO_NET_STATS_TYPE_RX_CSUM & vi->device_stats_cap) { + ctx->bitmap[queue_type] |= VIRTIO_NET_STATS_TYPE_RX_CSUM; + ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_rx_csum_desc_qstat); + ctx->size[queue_type] += sizeof(struct virtio_net_stats_rx_csum); + } + + if (VIRTIO_NET_STATS_TYPE_RX_GSO & vi->device_stats_cap) { + ctx->bitmap[queue_type] |= VIRTIO_NET_STATS_TYPE_RX_GSO; + ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_rx_gso_desc_qstat); + ctx->size[queue_type] += sizeof(struct virtio_net_stats_rx_gso); + } + + if (VIRTIO_NET_STATS_TYPE_RX_SPEED & vi->device_stats_cap) { + ctx->bitmap[queue_type] |= VIRTIO_NET_STATS_TYPE_RX_SPEED; + ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_rx_speed_desc_qstat); + ctx->size[queue_type] += sizeof(struct virtio_net_stats_rx_speed); + } + + queue_type = VIRTNET_Q_TYPE_TX; + + if (VIRTIO_NET_STATS_TYPE_TX_BASIC & vi->device_stats_cap) { + ctx->bitmap[queue_type] |= VIRTIO_NET_STATS_TYPE_TX_BASIC; + ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_tx_basic_desc_qstat); + ctx->size[queue_type] += sizeof(struct virtio_net_stats_tx_basic); + } + + if (VIRTIO_NET_STATS_TYPE_TX_CSUM & vi->device_stats_cap) { + ctx->bitmap[queue_type] |= VIRTIO_NET_STATS_TYPE_TX_CSUM; + ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_tx_csum_desc_qstat); + ctx->size[queue_type] += sizeof(struct virtio_net_stats_tx_csum); + } + + if (VIRTIO_NET_STATS_TYPE_TX_GSO & vi->device_stats_cap) { + ctx->bitmap[queue_type] |= VIRTIO_NET_STATS_TYPE_TX_GSO; + ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_tx_gso_desc_qstat); + ctx->size[queue_type] += sizeof(struct virtio_net_stats_tx_gso); + } + + if (VIRTIO_NET_STATS_TYPE_TX_SPEED & vi->device_stats_cap) { + ctx->bitmap[queue_type] |= VIRTIO_NET_STATS_TYPE_TX_SPEED; + ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_tx_speed_desc_qstat); + ctx->size[queue_type] += sizeof(struct virtio_net_stats_tx_speed); + } + + return; + } ctx->desc_num[VIRTNET_Q_TYPE_RX] = ARRAY_SIZE(virtnet_rq_stats_desc); ctx->desc_num[VIRTNET_Q_TYPE_TX] = ARRAY_SIZE(virtnet_sq_stats_desc); @@ -3551,7 +3698,104 @@ static void virtnet_fill_total_fields(struct virtnet_info *vi, stats_sum_queue(data, num_tx, first_tx_q, vi->curr_queue_pairs); } -/* virtnet_fill_stats - copy the stats to ethtool -S +static void virtnet_fill_stats_qstat(struct virtnet_info *vi, u32 qid, + struct virtnet_stats_ctx *ctx, + const u8 *base, bool drv_stats, u8 reply_type) +{ + const struct virtnet_stat_desc *desc; + const u64_stats_t *v_stat; + u64 offset, bitmap; + const __le64 *v; + u32 queue_type; + int i, num; + + queue_type = vq_type(vi, qid); + bitmap = ctx->bitmap[queue_type]; + + if (drv_stats) { + if (queue_type == VIRTNET_Q_TYPE_RX) { + desc = &virtnet_rq_stats_desc_qstat[0]; + num = ARRAY_SIZE(virtnet_rq_stats_desc_qstat); + } else { + desc = &virtnet_sq_stats_desc_qstat[0]; + num = ARRAY_SIZE(virtnet_sq_stats_desc_qstat); + } + + for (i = 0; i < num; ++i) { + offset = desc[i].qstat_offset / sizeof(*ctx->data); + v_stat = (const u64_stats_t *)(base + desc[i].offset); + ctx->data[offset] = u64_stats_read(v_stat); + } + return; + } + + if (VIRTIO_NET_STATS_TYPE_RX_BASIC & bitmap) { + desc = &virtnet_stats_rx_basic_desc_qstat[0]; + num = ARRAY_SIZE(virtnet_stats_rx_basic_desc_qstat); + if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_RX_BASIC) + goto found; + } + + if (VIRTIO_NET_STATS_TYPE_RX_CSUM & bitmap) { + desc = &virtnet_stats_rx_csum_desc_qstat[0]; + num = ARRAY_SIZE(virtnet_stats_rx_csum_desc_qstat); + if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_RX_CSUM) + goto found; + } + + if (VIRTIO_NET_STATS_TYPE_RX_GSO & bitmap) { + desc = &virtnet_stats_rx_gso_desc_qstat[0]; + num = ARRAY_SIZE(virtnet_stats_rx_gso_desc_qstat); + if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_RX_GSO) + goto found; + } + + if (VIRTIO_NET_STATS_TYPE_RX_SPEED & bitmap) { + desc = &virtnet_stats_rx_speed_desc_qstat[0]; + num = ARRAY_SIZE(virtnet_stats_rx_speed_desc_qstat); + if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_RX_SPEED) + goto found; + } + + if (VIRTIO_NET_STATS_TYPE_TX_BASIC & bitmap) { + desc = &virtnet_stats_tx_basic_desc_qstat[0]; + num = ARRAY_SIZE(virtnet_stats_tx_basic_desc_qstat); + if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_TX_BASIC) + goto found; + } + + if (VIRTIO_NET_STATS_TYPE_TX_CSUM & bitmap) { + desc = &virtnet_stats_tx_csum_desc_qstat[0]; + num = ARRAY_SIZE(virtnet_stats_tx_csum_desc_qstat); + if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_TX_CSUM) + goto found; + } + + if (VIRTIO_NET_STATS_TYPE_TX_GSO & bitmap) { + desc = &virtnet_stats_tx_gso_desc_qstat[0]; + num = ARRAY_SIZE(virtnet_stats_tx_gso_desc_qstat); + if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_TX_GSO) + goto found; + } + + if (VIRTIO_NET_STATS_TYPE_TX_SPEED & bitmap) { + desc = &virtnet_stats_tx_speed_desc_qstat[0]; + num = ARRAY_SIZE(virtnet_stats_tx_speed_desc_qstat); + if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_TX_SPEED) + goto found; + } + + return; + +found: + for (i = 0; i < num; ++i) { + offset = desc[i].qstat_offset / sizeof(*ctx->data); + v = (const __le64 *)(base + desc[i].offset); + ctx->data[offset] = le64_to_cpu(*v); + } +} + +/* virtnet_fill_stats - copy the stats to qstats or ethtool -S * The stats source is the device or the driver. * * @vi: virtio net info @@ -3572,6 +3816,9 @@ static void virtnet_fill_stats(struct virtnet_info *vi, u32 qid, const __le64 *v; int i, num; + if (ctx->to_qstat) + return virtnet_fill_stats_qstat(vi, qid, ctx, base, drv_stats, reply_type); + num_cq = ctx->desc_num[VIRTNET_Q_TYPE_CQ]; num_rx = ctx->desc_num[VIRTNET_Q_TYPE_RX]; num_tx = ctx->desc_num[VIRTNET_Q_TYPE_TX]; @@ -3731,22 +3978,34 @@ static void virtnet_make_stat_req(struct virtnet_info *vi, *idx += 1; } +/* qid: -1: get stats of all vq. + * > 0: get the stats for the special vq. This must not be cvq. + */ static int virtnet_get_hw_stats(struct virtnet_info *vi, - struct virtnet_stats_ctx *ctx) + struct virtnet_stats_ctx *ctx, int qid) { + int qnum, i, j, res_size, qtype, last_vq, first_vq; struct virtio_net_ctrl_queue_stats *req; - int qnum, i, j, res_size, qtype, last_vq; + bool enable_cvq; void *reply; int ok; if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_DEVICE_STATS)) return 0; - last_vq = vi->curr_queue_pairs * 2 - 1; + if (qid == -1) { + last_vq = vi->curr_queue_pairs * 2 - 1; + first_vq = 0; + enable_cvq = true; + } else { + last_vq = qid; + first_vq = qid; + enable_cvq = false; + } qnum = 0; res_size = 0; - for (i = 0; i <= last_vq ; ++i) { + for (i = first_vq; i <= last_vq ; ++i) { qtype = vq_type(vi, i); if (ctx->bitmap[qtype]) { ++qnum; @@ -3754,7 +4013,7 @@ static int virtnet_get_hw_stats(struct virtnet_info *vi, } } - if (ctx->bitmap[VIRTNET_Q_TYPE_CQ]) { + if (enable_cvq && ctx->bitmap[VIRTNET_Q_TYPE_CQ]) { res_size += ctx->size[VIRTNET_Q_TYPE_CQ]; qnum += 1; } @@ -3770,10 +4029,11 @@ static int virtnet_get_hw_stats(struct virtnet_info *vi, } j = 0; - for (i = 0; i <= last_vq ; ++i) + for (i = first_vq; i <= last_vq ; ++i) virtnet_make_stat_req(vi, ctx, req, i, &j); - virtnet_make_stat_req(vi, ctx, req, vi->max_queue_pairs * 2, &j); + if (enable_cvq) + virtnet_make_stat_req(vi, ctx, req, vi->max_queue_pairs * 2, &j); ok = __virtnet_get_hw_stats(vi, ctx, req, sizeof(*req) * j, reply, res_size); @@ -3814,7 +4074,7 @@ static int virtnet_get_sset_count(struct net_device *dev, int sset) switch (sset) { case ETH_SS_STATS: - virtnet_stats_ctx_init(vi, &ctx, NULL); + virtnet_stats_ctx_init(vi, &ctx, NULL, false); pair_count = ctx.desc_num[VIRTNET_Q_TYPE_RX] + ctx.desc_num[VIRTNET_Q_TYPE_TX]; @@ -3833,8 +4093,8 @@ static void virtnet_get_ethtool_stats(struct net_device *dev, unsigned int start, i; const u8 *stats_base; - virtnet_stats_ctx_init(vi, &ctx, data); - if (virtnet_get_hw_stats(vi, &ctx)) + virtnet_stats_ctx_init(vi, &ctx, data, false); + if (virtnet_get_hw_stats(vi, &ctx, -1)) dev_warn(&vi->dev->dev, "Failed to get hw stats.\n"); for (i = 0; i < vi->curr_queue_pairs; i++) { @@ -4373,6 +4633,72 @@ static const struct ethtool_ops virtnet_ethtool_ops = { .set_rxnfc = virtnet_set_rxnfc, }; +static void virtnet_get_queue_stats_rx(struct net_device *dev, int i, + struct netdev_queue_stats_rx *stats) +{ + struct virtnet_info *vi = netdev_priv(dev); + struct receive_queue *rq = &vi->rq[i]; + struct virtnet_stats_ctx ctx = {0}; + + virtnet_stats_ctx_init(vi, &ctx, (void *)stats, true); + + virtnet_get_hw_stats(vi, &ctx, i * 2); + virtnet_fill_stats(vi, i * 2, &ctx, (void *)&rq->stats, true, 0); +} + +static void virtnet_get_queue_stats_tx(struct net_device *dev, int i, + struct netdev_queue_stats_tx *stats) +{ + struct virtnet_info *vi = netdev_priv(dev); + struct send_queue *sq = &vi->sq[i]; + struct virtnet_stats_ctx ctx = {0}; + + virtnet_stats_ctx_init(vi, &ctx, (void *)stats, true); + + virtnet_get_hw_stats(vi, &ctx, i * 2 + 1); + virtnet_fill_stats(vi, i * 2 + 1, &ctx, (void *)&sq->stats, true, 0); +} + +static void virtnet_get_base_stats(struct net_device *dev, + struct netdev_queue_stats_rx *rx, + struct netdev_queue_stats_tx *tx) +{ + /* The queue stats of the virtio-net will not be reset. So here we + * return 0. + */ + rx->bytes = 0; + rx->packets = 0; + rx->alloc_fail = 0; + rx->hw_drops = 0; + rx->hw_drop_overruns = 0; + rx->csum_unnecessary = 0; + rx->csum_none = 0; + rx->csum_bad = 0; + rx->hw_gro_packets = 0; + rx->hw_gro_bytes = 0; + rx->hw_gro_wire_packets = 0; + rx->hw_gro_wire_bytes = 0; + rx->hw_drop_ratelimits = 0; + + tx->bytes = 0; + tx->packets = 0; + tx->hw_drops = 0; + tx->hw_drop_errors = 0; + tx->csum_none = 0; + tx->needs_csum = 0; + tx->hw_gso_packets = 0; + tx->hw_gso_bytes = 0; + tx->hw_gso_wire_packets = 0; + tx->hw_gso_wire_bytes = 0; + tx->hw_drop_ratelimits = 0; +} + +static const struct netdev_stat_ops virtnet_stat_ops = { + .get_queue_stats_rx = virtnet_get_queue_stats_rx, + .get_queue_stats_tx = virtnet_get_queue_stats_tx, + .get_base_stats = virtnet_get_base_stats, +}; + static void virtnet_freeze_down(struct virtio_device *vdev) { struct virtnet_info *vi = vdev->priv; @@ -5131,6 +5457,7 @@ static int virtnet_probe(struct virtio_device *vdev) dev->priv_flags |= IFF_UNICAST_FLT | IFF_LIVE_ADDR_CHANGE | IFF_TX_SKB_NO_LINEAR; dev->netdev_ops = &virtnet_netdev; + dev->stat_ops = &virtnet_stat_ops; dev->features = NETIF_F_HIGHDMA; dev->ethtool_ops = &virtnet_ethtool_ops;