All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 0/4] Added RSS support.
@ 2021-10-31  4:59 ` Andrew Melnychenko
  0 siblings, 0 replies; 27+ messages in thread
From: Andrew Melnychenko @ 2021-10-31  4:59 UTC (permalink / raw)
  To: mst, jasowang, davem, kuba
  Cc: yan, netdev, yuri.benditovich, linux-kernel, virtualization

This series of RFC patches for comments and additional proposals.

Virtio-net supports "hardware" RSS with toeplitz key.
Also, it allows receiving calculated hash in vheader
that may be used with RPS.
Added ethtools callbacks to manipulate RSS.

Technically hash calculation may be set only for
SRC+DST and SRC+DST+PORTSRC+PORTDST hashflows.
The completely disabling hash calculation for TCP or UDP
would disable hash calculation for IP.

RSS/RXHASH is disabled by default.

Changes since rfc:
* code refactored
* patches reformatted
* added feature validation

Andrew Melnychenko (4):
  drivers/net/virtio_net: Fixed vheader to use v1.
  drivers/net/virtio_net: Changed mergeable buffer length calculation.
  drivers/net/virtio_net: Added basic RSS support.
  drivers/net/virtio_net: Added RSS hash report control.

 drivers/net/virtio_net.c | 405 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 390 insertions(+), 15 deletions(-)

-- 
2.33.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [RFC PATCH 0/4] Added RSS support.
@ 2021-10-31  4:59 ` Andrew Melnychenko
  0 siblings, 0 replies; 27+ messages in thread
From: Andrew Melnychenko @ 2021-10-31  4:59 UTC (permalink / raw)
  To: mst, jasowang, davem, kuba
  Cc: virtualization, netdev, linux-kernel, yuri.benditovich, yan

This series of RFC patches for comments and additional proposals.

Virtio-net supports "hardware" RSS with toeplitz key.
Also, it allows receiving calculated hash in vheader
that may be used with RPS.
Added ethtools callbacks to manipulate RSS.

Technically hash calculation may be set only for
SRC+DST and SRC+DST+PORTSRC+PORTDST hashflows.
The completely disabling hash calculation for TCP or UDP
would disable hash calculation for IP.

RSS/RXHASH is disabled by default.

Changes since rfc:
* code refactored
* patches reformatted
* added feature validation

Andrew Melnychenko (4):
  drivers/net/virtio_net: Fixed vheader to use v1.
  drivers/net/virtio_net: Changed mergeable buffer length calculation.
  drivers/net/virtio_net: Added basic RSS support.
  drivers/net/virtio_net: Added RSS hash report control.

 drivers/net/virtio_net.c | 405 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 390 insertions(+), 15 deletions(-)

-- 
2.33.1


^ permalink raw reply	[flat|nested] 27+ messages in thread

* [RFC PATCH 1/4] drivers/net/virtio_net: Fixed vheader to use v1.
  2021-10-31  4:59 ` Andrew Melnychenko
@ 2021-10-31  4:59   ` Andrew Melnychenko
  -1 siblings, 0 replies; 27+ messages in thread
From: Andrew Melnychenko @ 2021-10-31  4:59 UTC (permalink / raw)
  To: mst, jasowang, davem, kuba
  Cc: yan, netdev, yuri.benditovich, linux-kernel, virtualization

The header v1 provides additional info about RSS.
Added changes to computing proper header length.
In the next patches, the header may contain RSS hash info
for the hash population.

Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
---
 drivers/net/virtio_net.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 4ad25a8b0870..b72b21ac8ebd 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -240,13 +240,13 @@ struct virtnet_info {
 };
 
 struct padded_vnet_hdr {
-	struct virtio_net_hdr_mrg_rxbuf hdr;
+	struct virtio_net_hdr_v1_hash hdr;
 	/*
 	 * hdr is in a separate sg buffer, and data sg buffer shares same page
 	 * with this header sg. This padding makes next sg 16 byte aligned
 	 * after the header.
 	 */
-	char padding[4];
+	char padding[12];
 };
 
 static bool is_xdp_frame(void *ptr)
@@ -1636,7 +1636,7 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
 	const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
 	struct virtnet_info *vi = sq->vq->vdev->priv;
 	int num_sg;
-	unsigned hdr_len = vi->hdr_len;
+	unsigned int hdr_len = vi->hdr_len;
 	bool can_push;
 
 	pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest);
-- 
2.33.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [RFC PATCH 1/4] drivers/net/virtio_net: Fixed vheader to use v1.
@ 2021-10-31  4:59   ` Andrew Melnychenko
  0 siblings, 0 replies; 27+ messages in thread
From: Andrew Melnychenko @ 2021-10-31  4:59 UTC (permalink / raw)
  To: mst, jasowang, davem, kuba
  Cc: virtualization, netdev, linux-kernel, yuri.benditovich, yan

The header v1 provides additional info about RSS.
Added changes to computing proper header length.
In the next patches, the header may contain RSS hash info
for the hash population.

Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
---
 drivers/net/virtio_net.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 4ad25a8b0870..b72b21ac8ebd 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -240,13 +240,13 @@ struct virtnet_info {
 };
 
 struct padded_vnet_hdr {
-	struct virtio_net_hdr_mrg_rxbuf hdr;
+	struct virtio_net_hdr_v1_hash hdr;
 	/*
 	 * hdr is in a separate sg buffer, and data sg buffer shares same page
 	 * with this header sg. This padding makes next sg 16 byte aligned
 	 * after the header.
 	 */
-	char padding[4];
+	char padding[12];
 };
 
 static bool is_xdp_frame(void *ptr)
@@ -1636,7 +1636,7 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
 	const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
 	struct virtnet_info *vi = sq->vq->vdev->priv;
 	int num_sg;
-	unsigned hdr_len = vi->hdr_len;
+	unsigned int hdr_len = vi->hdr_len;
 	bool can_push;
 
 	pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest);
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [RFC PATCH 2/4] drivers/net/virtio_net: Changed mergeable buffer length calculation.
  2021-10-31  4:59 ` Andrew Melnychenko
@ 2021-10-31  4:59   ` Andrew Melnychenko
  -1 siblings, 0 replies; 27+ messages in thread
From: Andrew Melnychenko @ 2021-10-31  4:59 UTC (permalink / raw)
  To: mst, jasowang, davem, kuba
  Cc: yan, netdev, yuri.benditovich, linux-kernel, virtualization

Now minimal virtual header length is may include the entire v1 header
if the hash report were populated.

Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
---
 drivers/net/virtio_net.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index b72b21ac8ebd..abca2e93355d 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -393,7 +393,9 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
 	hdr_p = p;
 
 	hdr_len = vi->hdr_len;
-	if (vi->mergeable_rx_bufs)
+	if (vi->has_rss_hash_report)
+		hdr_padded_len = sizeof(struct virtio_net_hdr_v1_hash);
+	else if (vi->mergeable_rx_bufs)
 		hdr_padded_len = sizeof(*hdr);
 	else
 		hdr_padded_len = sizeof(struct padded_vnet_hdr);
@@ -1252,7 +1254,7 @@ static unsigned int get_mergeable_buf_len(struct receive_queue *rq,
 					  struct ewma_pkt_len *avg_pkt_len,
 					  unsigned int room)
 {
-	const size_t hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+	const size_t hdr_len = ((struct virtnet_info *)(rq->vq->vdev->priv))->hdr_len;
 	unsigned int len;
 
 	if (room)
@@ -2817,7 +2819,7 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
  */
 static unsigned int mergeable_min_buf_len(struct virtnet_info *vi, struct virtqueue *vq)
 {
-	const unsigned int hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+	const unsigned int hdr_len = vi->hdr_len;
 	unsigned int rq_size = virtqueue_get_vring_size(vq);
 	unsigned int packet_len = vi->big_packets ? IP_MAX_MTU : vi->dev->max_mtu;
 	unsigned int buf_len = hdr_len + ETH_HLEN + VLAN_HLEN + packet_len;
-- 
2.33.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [RFC PATCH 2/4] drivers/net/virtio_net: Changed mergeable buffer length calculation.
@ 2021-10-31  4:59   ` Andrew Melnychenko
  0 siblings, 0 replies; 27+ messages in thread
From: Andrew Melnychenko @ 2021-10-31  4:59 UTC (permalink / raw)
  To: mst, jasowang, davem, kuba
  Cc: virtualization, netdev, linux-kernel, yuri.benditovich, yan

Now minimal virtual header length is may include the entire v1 header
if the hash report were populated.

Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
---
 drivers/net/virtio_net.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index b72b21ac8ebd..abca2e93355d 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -393,7 +393,9 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
 	hdr_p = p;
 
 	hdr_len = vi->hdr_len;
-	if (vi->mergeable_rx_bufs)
+	if (vi->has_rss_hash_report)
+		hdr_padded_len = sizeof(struct virtio_net_hdr_v1_hash);
+	else if (vi->mergeable_rx_bufs)
 		hdr_padded_len = sizeof(*hdr);
 	else
 		hdr_padded_len = sizeof(struct padded_vnet_hdr);
@@ -1252,7 +1254,7 @@ static unsigned int get_mergeable_buf_len(struct receive_queue *rq,
 					  struct ewma_pkt_len *avg_pkt_len,
 					  unsigned int room)
 {
-	const size_t hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+	const size_t hdr_len = ((struct virtnet_info *)(rq->vq->vdev->priv))->hdr_len;
 	unsigned int len;
 
 	if (room)
@@ -2817,7 +2819,7 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
  */
 static unsigned int mergeable_min_buf_len(struct virtnet_info *vi, struct virtqueue *vq)
 {
-	const unsigned int hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+	const unsigned int hdr_len = vi->hdr_len;
 	unsigned int rq_size = virtqueue_get_vring_size(vq);
 	unsigned int packet_len = vi->big_packets ? IP_MAX_MTU : vi->dev->max_mtu;
 	unsigned int buf_len = hdr_len + ETH_HLEN + VLAN_HLEN + packet_len;
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [RFC PATCH 3/4] drivers/net/virtio_net: Added basic RSS support.
  2021-10-31  4:59 ` Andrew Melnychenko
@ 2021-10-31  4:59   ` Andrew Melnychenko
  -1 siblings, 0 replies; 27+ messages in thread
From: Andrew Melnychenko @ 2021-10-31  4:59 UTC (permalink / raw)
  To: mst, jasowang, davem, kuba
  Cc: yan, netdev, yuri.benditovich, linux-kernel, virtualization

Added features for RSS and RSS hash report.
Added initialization, RXHASH feature and ethtool ops.
By default RSS/RXHASH is disabled.
Added ethtools ops to set key and indirection table.

Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
---
 drivers/net/virtio_net.c | 232 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 223 insertions(+), 9 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index abca2e93355d..cff7340f40bb 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -167,6 +167,28 @@ struct receive_queue {
 	struct xdp_rxq_info xdp_rxq;
 };
 
+/* This structure can contain rss message with maximum settings for indirection table and keysize
+ * Note, that default structure that describes RSS configuration virtio_net_rss_config
+ * contains same info but can't handle table values.
+ * In any case, structure would be passed to virtio hw through sg_buf split by parts
+ * because table sizes may be differ according to the device configuration.
+ */
+#define VIRTIO_NET_RSS_MAX_KEY_SIZE     40
+#define VIRTIO_NET_RSS_MAX_TABLE_LEN    128
+struct virtio_net_ctrl_rss {
+	struct {
+		__le32 hash_types;
+		__le16 indirection_table_mask;
+		__le16 unclassified_queue;
+	} __packed table_info;
+	u16 indirection_table[VIRTIO_NET_RSS_MAX_TABLE_LEN];
+	struct {
+		u16 max_tx_vq; /* queues */
+		u8 hash_key_length;
+	} __packed key_info;
+	u8 key[VIRTIO_NET_RSS_MAX_KEY_SIZE];
+};
+
 /* Control VQ buffers: protected by the rtnl lock */
 struct control_buf {
 	struct virtio_net_ctrl_hdr hdr;
@@ -176,6 +198,7 @@ struct control_buf {
 	u8 allmulti;
 	__virtio16 vid;
 	__virtio64 offloads;
+	struct virtio_net_ctrl_rss rss;
 };
 
 struct virtnet_info {
@@ -204,6 +227,12 @@ struct virtnet_info {
 	/* Host will merge rx buffers for big packets (shake it! shake it!) */
 	bool mergeable_rx_bufs;
 
+	/* Host supports rss and/or hash report */
+	bool has_rss;
+	bool has_rss_hash_report;
+	u8 rss_key_size;
+	u16 rss_indir_table_size;
+
 	/* Has control virtqueue */
 	bool has_cvq;
 
@@ -1119,6 +1148,8 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
 	struct net_device *dev = vi->dev;
 	struct sk_buff *skb;
 	struct virtio_net_hdr_mrg_rxbuf *hdr;
+	struct virtio_net_hdr_v1_hash *hdr_hash;
+	enum pkt_hash_types rss_hash_type;
 
 	if (unlikely(len < vi->hdr_len + ETH_HLEN)) {
 		pr_debug("%s: short packet %i\n", dev->name, len);
@@ -1145,6 +1176,29 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
 		return;
 
 	hdr = skb_vnet_hdr(skb);
+	if (vi->has_rss_hash_report && (dev->features & NETIF_F_RXHASH)) {
+		hdr_hash = (struct virtio_net_hdr_v1_hash *)(hdr);
+
+		switch (hdr_hash->hash_report) {
+		case VIRTIO_NET_HASH_REPORT_TCPv4:
+		case VIRTIO_NET_HASH_REPORT_UDPv4:
+		case VIRTIO_NET_HASH_REPORT_TCPv6:
+		case VIRTIO_NET_HASH_REPORT_UDPv6:
+		case VIRTIO_NET_HASH_REPORT_TCPv6_EX:
+		case VIRTIO_NET_HASH_REPORT_UDPv6_EX:
+			rss_hash_type = PKT_HASH_TYPE_L4;
+			break;
+		case VIRTIO_NET_HASH_REPORT_IPv4:
+		case VIRTIO_NET_HASH_REPORT_IPv6:
+		case VIRTIO_NET_HASH_REPORT_IPv6_EX:
+			rss_hash_type = PKT_HASH_TYPE_L3;
+			break;
+		case VIRTIO_NET_HASH_REPORT_NONE:
+		default:
+			rss_hash_type = PKT_HASH_TYPE_NONE;
+		}
+		skb_set_hash(skb, hdr_hash->hash_value, rss_hash_type);
+	}
 
 	if (hdr->hdr.flags & VIRTIO_NET_HDR_F_DATA_VALID)
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -2167,6 +2221,57 @@ static void virtnet_get_ringparam(struct net_device *dev,
 	ring->tx_pending = ring->tx_max_pending;
 }
 
+static bool virtnet_commit_rss_command(struct virtnet_info *vi)
+{
+	struct net_device *dev = vi->dev;
+	struct scatterlist sgs[4];
+	unsigned int sg_buf_size;
+
+	/* prepare sgs */
+	sg_init_table(sgs, 4);
+
+	sg_buf_size = sizeof(vi->ctrl->rss.table_info);
+	sg_set_buf(&sgs[0], &vi->ctrl->rss.table_info, sg_buf_size);
+
+	sg_buf_size = sizeof(uint16_t) * vi->rss_indir_table_size;
+	sg_set_buf(&sgs[1], vi->ctrl->rss.indirection_table, sg_buf_size);
+
+	sg_buf_size = sizeof(vi->ctrl->rss.key_info);
+	sg_set_buf(&sgs[2], &vi->ctrl->rss.key_info, sg_buf_size);
+
+	sg_buf_size = vi->rss_key_size;
+	sg_set_buf(&sgs[3], vi->ctrl->rss.key, sg_buf_size);
+
+	if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MQ,
+				  vi->has_rss ? VIRTIO_NET_CTRL_MQ_RSS_CONFIG
+				  : VIRTIO_NET_CTRL_MQ_HASH_CONFIG, sgs)) {
+		dev_warn(&dev->dev, "VIRTIONET issue with committing RSS sgs\n");
+		return false;
+	}
+	return true;
+}
+
+static void virtnet_init_default_rss(struct virtnet_info *vi)
+{
+	u32 indir_val = 0;
+	int i = 0;
+
+	vi->ctrl->rss.table_info.hash_types = vi->rss_hash_types_supported;
+	vi->rss_hash_types_saved = vi->rss_hash_types_supported;
+	vi->ctrl->rss.table_info.indirection_table_mask = vi->rss_indir_table_size - 1;
+	vi->ctrl->rss.table_info.unclassified_queue = 0;
+
+	for (; i < vi->rss_indir_table_size; ++i) {
+		indir_val = ethtool_rxfh_indir_default(i, vi->max_queue_pairs);
+		vi->ctrl->rss.indirection_table[i] = indir_val;
+	}
+
+	vi->ctrl->rss.key_info.max_tx_vq = vi->curr_queue_pairs;
+	vi->ctrl->rss.key_info.hash_key_length = vi->rss_key_size;
+
+	netdev_rss_key_fill(vi->ctrl->rss.key, vi->rss_key_size);
+}
+
 
 static void virtnet_get_drvinfo(struct net_device *dev,
 				struct ethtool_drvinfo *info)
@@ -2395,6 +2500,71 @@ static void virtnet_update_settings(struct virtnet_info *vi)
 		vi->duplex = duplex;
 }
 
+static u32 virtnet_get_rxfh_key_size(struct net_device *dev)
+{
+	return ((struct virtnet_info *)netdev_priv(dev))->rss_key_size;
+}
+
+static u32 virtnet_get_rxfh_indir_size(struct net_device *dev)
+{
+	return ((struct virtnet_info *)netdev_priv(dev))->rss_indir_table_size;
+}
+
+static int virtnet_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc)
+{
+	struct virtnet_info *vi = netdev_priv(dev);
+	int i;
+
+	if (indir) {
+		for (i = 0; i < vi->rss_indir_table_size; ++i)
+			indir[i] = vi->ctrl->rss.indirection_table[i];
+	}
+
+	if (key)
+		memcpy(key, vi->ctrl->rss.key, vi->rss_key_size);
+
+	if (hfunc)
+		*hfunc = ETH_RSS_HASH_TOP;
+
+	return 0;
+}
+
+static int virtnet_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key, const u8 hfunc)
+{
+	struct virtnet_info *vi = netdev_priv(dev);
+	int i;
+
+	if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
+		return -EOPNOTSUPP;
+
+	if (indir) {
+		for (i = 0; i < vi->rss_indir_table_size; ++i)
+			vi->ctrl->rss.indirection_table[i] = indir[i];
+	}
+	if (key)
+		memcpy(vi->ctrl->rss.key, key, vi->rss_key_size);
+
+	virtnet_commit_rss_command(vi);
+
+	return 0;
+}
+
+static int virtnet_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, u32 *rule_locs)
+{
+	struct virtnet_info *vi = netdev_priv(dev);
+	int rc = 0;
+
+	switch (info->cmd) {
+	case ETHTOOL_GRXRINGS:
+		info->data = vi->curr_queue_pairs;
+		break;
+	default:
+		rc = -EOPNOTSUPP;
+	}
+
+	return rc;
+}
+
 static const struct ethtool_ops virtnet_ethtool_ops = {
 	.supported_coalesce_params = ETHTOOL_COALESCE_MAX_FRAMES,
 	.get_drvinfo = virtnet_get_drvinfo,
@@ -2410,6 +2580,11 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
 	.set_link_ksettings = virtnet_set_link_ksettings,
 	.set_coalesce = virtnet_set_coalesce,
 	.get_coalesce = virtnet_get_coalesce,
+	.get_rxfh_key_size = virtnet_get_rxfh_key_size,
+	.get_rxfh_indir_size = virtnet_get_rxfh_indir_size,
+	.get_rxfh = virtnet_get_rxfh,
+	.set_rxfh = virtnet_set_rxfh,
+	.get_rxnfc = virtnet_get_rxnfc,
 };
 
 static void virtnet_freeze_down(struct virtio_device *vdev)
@@ -3040,7 +3215,10 @@ static bool virtnet_validate_features(struct virtio_device *vdev)
 			     "VIRTIO_NET_F_CTRL_VQ") ||
 	     VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_MQ, "VIRTIO_NET_F_CTRL_VQ") ||
 	     VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR,
-			     "VIRTIO_NET_F_CTRL_VQ"))) {
+			     "VIRTIO_NET_F_CTRL_VQ") ||
+	     VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_RSS, "VIRTIO_NET_F_RSS") ||
+	     VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_HASH_REPORT,
+			     "VIRTIO_NET_F_HASH_REPORT"))) {
 		return false;
 	}
 
@@ -3080,13 +3258,14 @@ static int virtnet_probe(struct virtio_device *vdev)
 	u16 max_queue_pairs;
 	int mtu;
 
-	/* Find if host supports multiqueue virtio_net device */
-	err = virtio_cread_feature(vdev, VIRTIO_NET_F_MQ,
-				   struct virtio_net_config,
-				   max_virtqueue_pairs, &max_queue_pairs);
+	/* Find if host supports multiqueue/rss virtio_net device */
+	max_queue_pairs = 0;
+	if (virtio_has_feature(vdev, VIRTIO_NET_F_MQ) || virtio_has_feature(vdev, VIRTIO_NET_F_RSS))
+		max_queue_pairs =
+		     virtio_cread16(vdev, offsetof(struct virtio_net_config, max_virtqueue_pairs));
 
 	/* We need at least 2 queue's */
-	if (err || max_queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
+	if (max_queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
 	    max_queue_pairs > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX ||
 	    !virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
 		max_queue_pairs = 1;
@@ -3170,8 +3349,36 @@ static int virtnet_probe(struct virtio_device *vdev)
 	if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
 		vi->mergeable_rx_bufs = true;
 
-	if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF) ||
-	    virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
+	if (virtio_has_feature(vdev, VIRTIO_NET_F_HASH_REPORT)) {
+		vi->has_rss_hash_report = true;
+		vi->rss_indir_table_size = 1;
+		vi->rss_key_size = VIRTIO_NET_RSS_MAX_KEY_SIZE;
+	}
+
+	if (virtio_has_feature(vdev, VIRTIO_NET_F_RSS)) {
+		vi->has_rss = true;
+		vi->rss_indir_table_size =
+			virtio_cread16(vdev, offsetof(struct virtio_net_config,
+						      rss_max_indirection_table_length));
+		vi->rss_key_size =
+			virtio_cread8(vdev, offsetof(struct virtio_net_config, rss_max_key_size));
+	}
+
+	if (vi->has_rss || vi->has_rss_hash_report) {
+		vi->rss_hash_types_supported =
+		    virtio_cread32(vdev, offsetof(struct virtio_net_config, supported_hash_types));
+		vi->rss_hash_types_supported &=
+				~(VIRTIO_NET_RSS_HASH_TYPE_IP_EX |
+				  VIRTIO_NET_RSS_HASH_TYPE_TCP_EX |
+				  VIRTIO_NET_RSS_HASH_TYPE_UDP_EX);
+
+		dev->hw_features |= NETIF_F_RXHASH;
+	}
+
+	if (vi->has_rss_hash_report)
+		vi->hdr_len = sizeof(struct virtio_net_hdr_v1_hash);
+	else if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF) ||
+		 virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
 		vi->hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
 	else
 		vi->hdr_len = sizeof(struct virtio_net_hdr);
@@ -3238,6 +3445,12 @@ static int virtnet_probe(struct virtio_device *vdev)
 		}
 	}
 
+	if (vi->has_rss || vi->has_rss_hash_report) {
+		rtnl_lock();
+		virtnet_init_default_rss(vi);
+		rtnl_unlock();
+	}
+
 	err = register_netdev(dev);
 	if (err) {
 		pr_debug("virtio_net: registering device failed\n");
@@ -3369,7 +3582,8 @@ static struct virtio_device_id id_table[] = {
 	VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, \
 	VIRTIO_NET_F_CTRL_MAC_ADDR, \
 	VIRTIO_NET_F_MTU, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, \
-	VIRTIO_NET_F_SPEED_DUPLEX, VIRTIO_NET_F_STANDBY
+	VIRTIO_NET_F_SPEED_DUPLEX, VIRTIO_NET_F_STANDBY, \
+	VIRTIO_NET_F_RSS, VIRTIO_NET_F_HASH_REPORT
 
 static unsigned int features[] = {
 	VIRTNET_FEATURES,
-- 
2.33.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [RFC PATCH 3/4] drivers/net/virtio_net: Added basic RSS support.
@ 2021-10-31  4:59   ` Andrew Melnychenko
  0 siblings, 0 replies; 27+ messages in thread
From: Andrew Melnychenko @ 2021-10-31  4:59 UTC (permalink / raw)
  To: mst, jasowang, davem, kuba
  Cc: virtualization, netdev, linux-kernel, yuri.benditovich, yan

Added features for RSS and RSS hash report.
Added initialization, RXHASH feature and ethtool ops.
By default RSS/RXHASH is disabled.
Added ethtools ops to set key and indirection table.

Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
---
 drivers/net/virtio_net.c | 232 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 223 insertions(+), 9 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index abca2e93355d..cff7340f40bb 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -167,6 +167,28 @@ struct receive_queue {
 	struct xdp_rxq_info xdp_rxq;
 };
 
+/* This structure can contain rss message with maximum settings for indirection table and keysize
+ * Note, that default structure that describes RSS configuration virtio_net_rss_config
+ * contains same info but can't handle table values.
+ * In any case, structure would be passed to virtio hw through sg_buf split by parts
+ * because table sizes may be differ according to the device configuration.
+ */
+#define VIRTIO_NET_RSS_MAX_KEY_SIZE     40
+#define VIRTIO_NET_RSS_MAX_TABLE_LEN    128
+struct virtio_net_ctrl_rss {
+	struct {
+		__le32 hash_types;
+		__le16 indirection_table_mask;
+		__le16 unclassified_queue;
+	} __packed table_info;
+	u16 indirection_table[VIRTIO_NET_RSS_MAX_TABLE_LEN];
+	struct {
+		u16 max_tx_vq; /* queues */
+		u8 hash_key_length;
+	} __packed key_info;
+	u8 key[VIRTIO_NET_RSS_MAX_KEY_SIZE];
+};
+
 /* Control VQ buffers: protected by the rtnl lock */
 struct control_buf {
 	struct virtio_net_ctrl_hdr hdr;
@@ -176,6 +198,7 @@ struct control_buf {
 	u8 allmulti;
 	__virtio16 vid;
 	__virtio64 offloads;
+	struct virtio_net_ctrl_rss rss;
 };
 
 struct virtnet_info {
@@ -204,6 +227,12 @@ struct virtnet_info {
 	/* Host will merge rx buffers for big packets (shake it! shake it!) */
 	bool mergeable_rx_bufs;
 
+	/* Host supports rss and/or hash report */
+	bool has_rss;
+	bool has_rss_hash_report;
+	u8 rss_key_size;
+	u16 rss_indir_table_size;
+
 	/* Has control virtqueue */
 	bool has_cvq;
 
@@ -1119,6 +1148,8 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
 	struct net_device *dev = vi->dev;
 	struct sk_buff *skb;
 	struct virtio_net_hdr_mrg_rxbuf *hdr;
+	struct virtio_net_hdr_v1_hash *hdr_hash;
+	enum pkt_hash_types rss_hash_type;
 
 	if (unlikely(len < vi->hdr_len + ETH_HLEN)) {
 		pr_debug("%s: short packet %i\n", dev->name, len);
@@ -1145,6 +1176,29 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
 		return;
 
 	hdr = skb_vnet_hdr(skb);
+	if (vi->has_rss_hash_report && (dev->features & NETIF_F_RXHASH)) {
+		hdr_hash = (struct virtio_net_hdr_v1_hash *)(hdr);
+
+		switch (hdr_hash->hash_report) {
+		case VIRTIO_NET_HASH_REPORT_TCPv4:
+		case VIRTIO_NET_HASH_REPORT_UDPv4:
+		case VIRTIO_NET_HASH_REPORT_TCPv6:
+		case VIRTIO_NET_HASH_REPORT_UDPv6:
+		case VIRTIO_NET_HASH_REPORT_TCPv6_EX:
+		case VIRTIO_NET_HASH_REPORT_UDPv6_EX:
+			rss_hash_type = PKT_HASH_TYPE_L4;
+			break;
+		case VIRTIO_NET_HASH_REPORT_IPv4:
+		case VIRTIO_NET_HASH_REPORT_IPv6:
+		case VIRTIO_NET_HASH_REPORT_IPv6_EX:
+			rss_hash_type = PKT_HASH_TYPE_L3;
+			break;
+		case VIRTIO_NET_HASH_REPORT_NONE:
+		default:
+			rss_hash_type = PKT_HASH_TYPE_NONE;
+		}
+		skb_set_hash(skb, hdr_hash->hash_value, rss_hash_type);
+	}
 
 	if (hdr->hdr.flags & VIRTIO_NET_HDR_F_DATA_VALID)
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -2167,6 +2221,57 @@ static void virtnet_get_ringparam(struct net_device *dev,
 	ring->tx_pending = ring->tx_max_pending;
 }
 
+static bool virtnet_commit_rss_command(struct virtnet_info *vi)
+{
+	struct net_device *dev = vi->dev;
+	struct scatterlist sgs[4];
+	unsigned int sg_buf_size;
+
+	/* prepare sgs */
+	sg_init_table(sgs, 4);
+
+	sg_buf_size = sizeof(vi->ctrl->rss.table_info);
+	sg_set_buf(&sgs[0], &vi->ctrl->rss.table_info, sg_buf_size);
+
+	sg_buf_size = sizeof(uint16_t) * vi->rss_indir_table_size;
+	sg_set_buf(&sgs[1], vi->ctrl->rss.indirection_table, sg_buf_size);
+
+	sg_buf_size = sizeof(vi->ctrl->rss.key_info);
+	sg_set_buf(&sgs[2], &vi->ctrl->rss.key_info, sg_buf_size);
+
+	sg_buf_size = vi->rss_key_size;
+	sg_set_buf(&sgs[3], vi->ctrl->rss.key, sg_buf_size);
+
+	if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MQ,
+				  vi->has_rss ? VIRTIO_NET_CTRL_MQ_RSS_CONFIG
+				  : VIRTIO_NET_CTRL_MQ_HASH_CONFIG, sgs)) {
+		dev_warn(&dev->dev, "VIRTIONET issue with committing RSS sgs\n");
+		return false;
+	}
+	return true;
+}
+
+static void virtnet_init_default_rss(struct virtnet_info *vi)
+{
+	u32 indir_val = 0;
+	int i = 0;
+
+	vi->ctrl->rss.table_info.hash_types = vi->rss_hash_types_supported;
+	vi->rss_hash_types_saved = vi->rss_hash_types_supported;
+	vi->ctrl->rss.table_info.indirection_table_mask = vi->rss_indir_table_size - 1;
+	vi->ctrl->rss.table_info.unclassified_queue = 0;
+
+	for (; i < vi->rss_indir_table_size; ++i) {
+		indir_val = ethtool_rxfh_indir_default(i, vi->max_queue_pairs);
+		vi->ctrl->rss.indirection_table[i] = indir_val;
+	}
+
+	vi->ctrl->rss.key_info.max_tx_vq = vi->curr_queue_pairs;
+	vi->ctrl->rss.key_info.hash_key_length = vi->rss_key_size;
+
+	netdev_rss_key_fill(vi->ctrl->rss.key, vi->rss_key_size);
+}
+
 
 static void virtnet_get_drvinfo(struct net_device *dev,
 				struct ethtool_drvinfo *info)
@@ -2395,6 +2500,71 @@ static void virtnet_update_settings(struct virtnet_info *vi)
 		vi->duplex = duplex;
 }
 
+static u32 virtnet_get_rxfh_key_size(struct net_device *dev)
+{
+	return ((struct virtnet_info *)netdev_priv(dev))->rss_key_size;
+}
+
+static u32 virtnet_get_rxfh_indir_size(struct net_device *dev)
+{
+	return ((struct virtnet_info *)netdev_priv(dev))->rss_indir_table_size;
+}
+
+static int virtnet_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc)
+{
+	struct virtnet_info *vi = netdev_priv(dev);
+	int i;
+
+	if (indir) {
+		for (i = 0; i < vi->rss_indir_table_size; ++i)
+			indir[i] = vi->ctrl->rss.indirection_table[i];
+	}
+
+	if (key)
+		memcpy(key, vi->ctrl->rss.key, vi->rss_key_size);
+
+	if (hfunc)
+		*hfunc = ETH_RSS_HASH_TOP;
+
+	return 0;
+}
+
+static int virtnet_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key, const u8 hfunc)
+{
+	struct virtnet_info *vi = netdev_priv(dev);
+	int i;
+
+	if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
+		return -EOPNOTSUPP;
+
+	if (indir) {
+		for (i = 0; i < vi->rss_indir_table_size; ++i)
+			vi->ctrl->rss.indirection_table[i] = indir[i];
+	}
+	if (key)
+		memcpy(vi->ctrl->rss.key, key, vi->rss_key_size);
+
+	virtnet_commit_rss_command(vi);
+
+	return 0;
+}
+
+static int virtnet_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, u32 *rule_locs)
+{
+	struct virtnet_info *vi = netdev_priv(dev);
+	int rc = 0;
+
+	switch (info->cmd) {
+	case ETHTOOL_GRXRINGS:
+		info->data = vi->curr_queue_pairs;
+		break;
+	default:
+		rc = -EOPNOTSUPP;
+	}
+
+	return rc;
+}
+
 static const struct ethtool_ops virtnet_ethtool_ops = {
 	.supported_coalesce_params = ETHTOOL_COALESCE_MAX_FRAMES,
 	.get_drvinfo = virtnet_get_drvinfo,
@@ -2410,6 +2580,11 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
 	.set_link_ksettings = virtnet_set_link_ksettings,
 	.set_coalesce = virtnet_set_coalesce,
 	.get_coalesce = virtnet_get_coalesce,
+	.get_rxfh_key_size = virtnet_get_rxfh_key_size,
+	.get_rxfh_indir_size = virtnet_get_rxfh_indir_size,
+	.get_rxfh = virtnet_get_rxfh,
+	.set_rxfh = virtnet_set_rxfh,
+	.get_rxnfc = virtnet_get_rxnfc,
 };
 
 static void virtnet_freeze_down(struct virtio_device *vdev)
@@ -3040,7 +3215,10 @@ static bool virtnet_validate_features(struct virtio_device *vdev)
 			     "VIRTIO_NET_F_CTRL_VQ") ||
 	     VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_MQ, "VIRTIO_NET_F_CTRL_VQ") ||
 	     VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR,
-			     "VIRTIO_NET_F_CTRL_VQ"))) {
+			     "VIRTIO_NET_F_CTRL_VQ") ||
+	     VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_RSS, "VIRTIO_NET_F_RSS") ||
+	     VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_HASH_REPORT,
+			     "VIRTIO_NET_F_HASH_REPORT"))) {
 		return false;
 	}
 
@@ -3080,13 +3258,14 @@ static int virtnet_probe(struct virtio_device *vdev)
 	u16 max_queue_pairs;
 	int mtu;
 
-	/* Find if host supports multiqueue virtio_net device */
-	err = virtio_cread_feature(vdev, VIRTIO_NET_F_MQ,
-				   struct virtio_net_config,
-				   max_virtqueue_pairs, &max_queue_pairs);
+	/* Find if host supports multiqueue/rss virtio_net device */
+	max_queue_pairs = 0;
+	if (virtio_has_feature(vdev, VIRTIO_NET_F_MQ) || virtio_has_feature(vdev, VIRTIO_NET_F_RSS))
+		max_queue_pairs =
+		     virtio_cread16(vdev, offsetof(struct virtio_net_config, max_virtqueue_pairs));
 
 	/* We need at least 2 queue's */
-	if (err || max_queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
+	if (max_queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
 	    max_queue_pairs > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX ||
 	    !virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
 		max_queue_pairs = 1;
@@ -3170,8 +3349,36 @@ static int virtnet_probe(struct virtio_device *vdev)
 	if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
 		vi->mergeable_rx_bufs = true;
 
-	if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF) ||
-	    virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
+	if (virtio_has_feature(vdev, VIRTIO_NET_F_HASH_REPORT)) {
+		vi->has_rss_hash_report = true;
+		vi->rss_indir_table_size = 1;
+		vi->rss_key_size = VIRTIO_NET_RSS_MAX_KEY_SIZE;
+	}
+
+	if (virtio_has_feature(vdev, VIRTIO_NET_F_RSS)) {
+		vi->has_rss = true;
+		vi->rss_indir_table_size =
+			virtio_cread16(vdev, offsetof(struct virtio_net_config,
+						      rss_max_indirection_table_length));
+		vi->rss_key_size =
+			virtio_cread8(vdev, offsetof(struct virtio_net_config, rss_max_key_size));
+	}
+
+	if (vi->has_rss || vi->has_rss_hash_report) {
+		vi->rss_hash_types_supported =
+		    virtio_cread32(vdev, offsetof(struct virtio_net_config, supported_hash_types));
+		vi->rss_hash_types_supported &=
+				~(VIRTIO_NET_RSS_HASH_TYPE_IP_EX |
+				  VIRTIO_NET_RSS_HASH_TYPE_TCP_EX |
+				  VIRTIO_NET_RSS_HASH_TYPE_UDP_EX);
+
+		dev->hw_features |= NETIF_F_RXHASH;
+	}
+
+	if (vi->has_rss_hash_report)
+		vi->hdr_len = sizeof(struct virtio_net_hdr_v1_hash);
+	else if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF) ||
+		 virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
 		vi->hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
 	else
 		vi->hdr_len = sizeof(struct virtio_net_hdr);
@@ -3238,6 +3445,12 @@ static int virtnet_probe(struct virtio_device *vdev)
 		}
 	}
 
+	if (vi->has_rss || vi->has_rss_hash_report) {
+		rtnl_lock();
+		virtnet_init_default_rss(vi);
+		rtnl_unlock();
+	}
+
 	err = register_netdev(dev);
 	if (err) {
 		pr_debug("virtio_net: registering device failed\n");
@@ -3369,7 +3582,8 @@ static struct virtio_device_id id_table[] = {
 	VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, \
 	VIRTIO_NET_F_CTRL_MAC_ADDR, \
 	VIRTIO_NET_F_MTU, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, \
-	VIRTIO_NET_F_SPEED_DUPLEX, VIRTIO_NET_F_STANDBY
+	VIRTIO_NET_F_SPEED_DUPLEX, VIRTIO_NET_F_STANDBY, \
+	VIRTIO_NET_F_RSS, VIRTIO_NET_F_HASH_REPORT
 
 static unsigned int features[] = {
 	VIRTNET_FEATURES,
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [RFC PATCH 4/4] drivers/net/virtio_net: Added RSS hash report control.
  2021-10-31  4:59 ` Andrew Melnychenko
@ 2021-10-31  4:59   ` Andrew Melnychenko
  -1 siblings, 0 replies; 27+ messages in thread
From: Andrew Melnychenko @ 2021-10-31  4:59 UTC (permalink / raw)
  To: mst, jasowang, davem, kuba
  Cc: yan, netdev, yuri.benditovich, linux-kernel, virtualization

Added set_hash for skb.
Also added hashflow set/get callbacks.
Virtio RSS "IPv6 extensions" hashes disabled.
Also, disabling RXH_IP_SRC/DST for TCP would disable then for UDP.
TCP and UDP supports only:
ethtool -U eth0 rx-flow-hash tcp4 sd
    RXH_IP_SRC + RXH_IP_DST
ethtool -U eth0 rx-flow-hash tcp4 sdfn
    RXH_IP_SRC + RXH_IP_DST + RXH_L4_B_0_1 + RXH_L4_B_2_3

Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
---
 drivers/net/virtio_net.c | 159 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 159 insertions(+)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index cff7340f40bb..b1ed373d942b 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -232,6 +232,8 @@ struct virtnet_info {
 	bool has_rss_hash_report;
 	u8 rss_key_size;
 	u16 rss_indir_table_size;
+	u32 rss_hash_types_supported;
+	u32 rss_hash_types_saved;
 
 	/* Has control virtqueue */
 	bool has_cvq;
@@ -2272,6 +2274,131 @@ static void virtnet_init_default_rss(struct virtnet_info *vi)
 	netdev_rss_key_fill(vi->ctrl->rss.key, vi->rss_key_size);
 }
 
+static void virtnet_get_hashflow(const struct virtnet_info *vi, struct ethtool_rxnfc *info)
+{
+	info->data = 0;
+	switch (info->flow_type) {
+	case TCP_V4_FLOW:
+		if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_TCPv4) {
+			info->data = RXH_IP_SRC | RXH_IP_DST |
+						 RXH_L4_B_0_1 | RXH_L4_B_2_3;
+		} else if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv4) {
+			info->data = RXH_IP_SRC | RXH_IP_DST;
+		}
+		break;
+	case TCP_V6_FLOW:
+		if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_TCPv6) {
+			info->data = RXH_IP_SRC | RXH_IP_DST |
+						 RXH_L4_B_0_1 | RXH_L4_B_2_3;
+		} else if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv6) {
+			info->data = RXH_IP_SRC | RXH_IP_DST;
+		}
+		break;
+	case UDP_V4_FLOW:
+		if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_UDPv4) {
+			info->data = RXH_IP_SRC | RXH_IP_DST |
+						 RXH_L4_B_0_1 | RXH_L4_B_2_3;
+		} else if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv4) {
+			info->data = RXH_IP_SRC | RXH_IP_DST;
+		}
+		break;
+	case UDP_V6_FLOW:
+		if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_UDPv6) {
+			info->data = RXH_IP_SRC | RXH_IP_DST |
+						 RXH_L4_B_0_1 | RXH_L4_B_2_3;
+		} else if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv6) {
+			info->data = RXH_IP_SRC | RXH_IP_DST;
+		}
+		break;
+	case IPV4_FLOW:
+		if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv4)
+			info->data = RXH_IP_SRC | RXH_IP_DST;
+
+		break;
+	case IPV6_FLOW:
+		if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv4)
+			info->data = RXH_IP_SRC | RXH_IP_DST;
+
+		break;
+	default:
+		info->data = 0;
+		break;
+	}
+}
+
+static bool virtnet_set_hashflow(struct virtnet_info *vi, struct ethtool_rxnfc *info)
+{
+	u64 is_iphash = info->data & (RXH_IP_SRC | RXH_IP_DST);
+	u64 is_porthash = info->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3);
+	u32 new_hashtypes = vi->rss_hash_types_saved;
+
+	if ((is_iphash && (is_iphash != (RXH_IP_SRC | RXH_IP_DST))) ||
+	    (is_porthash && (is_porthash != (RXH_L4_B_0_1 | RXH_L4_B_2_3)))) {
+		return false;
+	}
+
+	if (!is_iphash && is_porthash)
+		return false;
+
+	switch (info->flow_type) {
+	case TCP_V4_FLOW:
+	case UDP_V4_FLOW:
+	case IPV4_FLOW:
+		new_hashtypes &= ~VIRTIO_NET_RSS_HASH_TYPE_IPv4;
+		if (is_iphash)
+			new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_IPv4;
+
+		break;
+	case TCP_V6_FLOW:
+	case UDP_V6_FLOW:
+	case IPV6_FLOW:
+		new_hashtypes &= ~VIRTIO_NET_RSS_HASH_TYPE_IPv6;
+		if (is_iphash)
+			new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_IPv6;
+
+		break;
+	default:
+		break;
+	}
+
+	switch (info->flow_type) {
+	case TCP_V4_FLOW:
+		new_hashtypes &= ~VIRTIO_NET_RSS_HASH_TYPE_TCPv4;
+		if (is_porthash)
+			new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_TCPv4;
+
+		break;
+	case UDP_V4_FLOW:
+		new_hashtypes &= ~VIRTIO_NET_RSS_HASH_TYPE_UDPv4;
+		if (is_porthash)
+			new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_UDPv4;
+
+		break;
+	case TCP_V6_FLOW:
+		new_hashtypes &= ~VIRTIO_NET_RSS_HASH_TYPE_TCPv6;
+		if (is_porthash)
+			new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_TCPv6;
+
+		break;
+	case UDP_V6_FLOW:
+		new_hashtypes &= ~VIRTIO_NET_RSS_HASH_TYPE_UDPv6;
+		if (is_porthash)
+			new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_UDPv6;
+
+		break;
+	default:
+		break;
+	}
+
+	if (new_hashtypes != vi->rss_hash_types_saved) {
+		vi->rss_hash_types_saved = new_hashtypes;
+		vi->ctrl->rss.table_info.hash_types = vi->rss_hash_types_saved;
+		if (vi->dev->features & NETIF_F_RXHASH)
+			return virtnet_commit_rss_command(vi);
+	}
+
+	return true;
+}
 
 static void virtnet_get_drvinfo(struct net_device *dev,
 				struct ethtool_drvinfo *info)
@@ -2557,6 +2684,27 @@ static int virtnet_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
 	switch (info->cmd) {
 	case ETHTOOL_GRXRINGS:
 		info->data = vi->curr_queue_pairs;
+		break;
+	case ETHTOOL_GRXFH:
+		virtnet_get_hashflow(vi, info);
+		break;
+	default:
+		rc = -EOPNOTSUPP;
+	}
+
+	return rc;
+}
+
+static int virtnet_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info)
+{
+	struct virtnet_info *vi = netdev_priv(dev);
+	int rc = 0;
+
+	switch (info->cmd) {
+	case ETHTOOL_SRXFH:
+		if (!virtnet_set_hashflow(vi, info))
+			rc = -EINVAL;
+
 		break;
 	default:
 		rc = -EOPNOTSUPP;
@@ -2585,6 +2733,7 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
 	.get_rxfh = virtnet_get_rxfh,
 	.set_rxfh = virtnet_set_rxfh,
 	.get_rxnfc = virtnet_get_rxnfc,
+	.set_rxnfc = virtnet_set_rxnfc,
 };
 
 static void virtnet_freeze_down(struct virtio_device *vdev)
@@ -2837,6 +2986,16 @@ static int virtnet_set_features(struct net_device *dev,
 		vi->guest_offloads = offloads;
 	}
 
+	if ((dev->features ^ features) & NETIF_F_RXHASH) {
+		if (features & NETIF_F_RXHASH)
+			vi->ctrl->rss.table_info.hash_types = vi->rss_hash_types_saved;
+		else
+			vi->ctrl->rss.table_info.hash_types = 0;
+
+		if (!virtnet_commit_rss_command(vi))
+			return -EINVAL;
+	}
+
 	return 0;
 }
 
-- 
2.33.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [RFC PATCH 4/4] drivers/net/virtio_net: Added RSS hash report control.
@ 2021-10-31  4:59   ` Andrew Melnychenko
  0 siblings, 0 replies; 27+ messages in thread
From: Andrew Melnychenko @ 2021-10-31  4:59 UTC (permalink / raw)
  To: mst, jasowang, davem, kuba
  Cc: virtualization, netdev, linux-kernel, yuri.benditovich, yan

Added set_hash for skb.
Also added hashflow set/get callbacks.
Virtio RSS "IPv6 extensions" hashes disabled.
Also, disabling RXH_IP_SRC/DST for TCP would disable then for UDP.
TCP and UDP supports only:
ethtool -U eth0 rx-flow-hash tcp4 sd
    RXH_IP_SRC + RXH_IP_DST
ethtool -U eth0 rx-flow-hash tcp4 sdfn
    RXH_IP_SRC + RXH_IP_DST + RXH_L4_B_0_1 + RXH_L4_B_2_3

Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
---
 drivers/net/virtio_net.c | 159 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 159 insertions(+)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index cff7340f40bb..b1ed373d942b 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -232,6 +232,8 @@ struct virtnet_info {
 	bool has_rss_hash_report;
 	u8 rss_key_size;
 	u16 rss_indir_table_size;
+	u32 rss_hash_types_supported;
+	u32 rss_hash_types_saved;
 
 	/* Has control virtqueue */
 	bool has_cvq;
@@ -2272,6 +2274,131 @@ static void virtnet_init_default_rss(struct virtnet_info *vi)
 	netdev_rss_key_fill(vi->ctrl->rss.key, vi->rss_key_size);
 }
 
+static void virtnet_get_hashflow(const struct virtnet_info *vi, struct ethtool_rxnfc *info)
+{
+	info->data = 0;
+	switch (info->flow_type) {
+	case TCP_V4_FLOW:
+		if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_TCPv4) {
+			info->data = RXH_IP_SRC | RXH_IP_DST |
+						 RXH_L4_B_0_1 | RXH_L4_B_2_3;
+		} else if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv4) {
+			info->data = RXH_IP_SRC | RXH_IP_DST;
+		}
+		break;
+	case TCP_V6_FLOW:
+		if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_TCPv6) {
+			info->data = RXH_IP_SRC | RXH_IP_DST |
+						 RXH_L4_B_0_1 | RXH_L4_B_2_3;
+		} else if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv6) {
+			info->data = RXH_IP_SRC | RXH_IP_DST;
+		}
+		break;
+	case UDP_V4_FLOW:
+		if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_UDPv4) {
+			info->data = RXH_IP_SRC | RXH_IP_DST |
+						 RXH_L4_B_0_1 | RXH_L4_B_2_3;
+		} else if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv4) {
+			info->data = RXH_IP_SRC | RXH_IP_DST;
+		}
+		break;
+	case UDP_V6_FLOW:
+		if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_UDPv6) {
+			info->data = RXH_IP_SRC | RXH_IP_DST |
+						 RXH_L4_B_0_1 | RXH_L4_B_2_3;
+		} else if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv6) {
+			info->data = RXH_IP_SRC | RXH_IP_DST;
+		}
+		break;
+	case IPV4_FLOW:
+		if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv4)
+			info->data = RXH_IP_SRC | RXH_IP_DST;
+
+		break;
+	case IPV6_FLOW:
+		if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv4)
+			info->data = RXH_IP_SRC | RXH_IP_DST;
+
+		break;
+	default:
+		info->data = 0;
+		break;
+	}
+}
+
+static bool virtnet_set_hashflow(struct virtnet_info *vi, struct ethtool_rxnfc *info)
+{
+	u64 is_iphash = info->data & (RXH_IP_SRC | RXH_IP_DST);
+	u64 is_porthash = info->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3);
+	u32 new_hashtypes = vi->rss_hash_types_saved;
+
+	if ((is_iphash && (is_iphash != (RXH_IP_SRC | RXH_IP_DST))) ||
+	    (is_porthash && (is_porthash != (RXH_L4_B_0_1 | RXH_L4_B_2_3)))) {
+		return false;
+	}
+
+	if (!is_iphash && is_porthash)
+		return false;
+
+	switch (info->flow_type) {
+	case TCP_V4_FLOW:
+	case UDP_V4_FLOW:
+	case IPV4_FLOW:
+		new_hashtypes &= ~VIRTIO_NET_RSS_HASH_TYPE_IPv4;
+		if (is_iphash)
+			new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_IPv4;
+
+		break;
+	case TCP_V6_FLOW:
+	case UDP_V6_FLOW:
+	case IPV6_FLOW:
+		new_hashtypes &= ~VIRTIO_NET_RSS_HASH_TYPE_IPv6;
+		if (is_iphash)
+			new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_IPv6;
+
+		break;
+	default:
+		break;
+	}
+
+	switch (info->flow_type) {
+	case TCP_V4_FLOW:
+		new_hashtypes &= ~VIRTIO_NET_RSS_HASH_TYPE_TCPv4;
+		if (is_porthash)
+			new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_TCPv4;
+
+		break;
+	case UDP_V4_FLOW:
+		new_hashtypes &= ~VIRTIO_NET_RSS_HASH_TYPE_UDPv4;
+		if (is_porthash)
+			new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_UDPv4;
+
+		break;
+	case TCP_V6_FLOW:
+		new_hashtypes &= ~VIRTIO_NET_RSS_HASH_TYPE_TCPv6;
+		if (is_porthash)
+			new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_TCPv6;
+
+		break;
+	case UDP_V6_FLOW:
+		new_hashtypes &= ~VIRTIO_NET_RSS_HASH_TYPE_UDPv6;
+		if (is_porthash)
+			new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_UDPv6;
+
+		break;
+	default:
+		break;
+	}
+
+	if (new_hashtypes != vi->rss_hash_types_saved) {
+		vi->rss_hash_types_saved = new_hashtypes;
+		vi->ctrl->rss.table_info.hash_types = vi->rss_hash_types_saved;
+		if (vi->dev->features & NETIF_F_RXHASH)
+			return virtnet_commit_rss_command(vi);
+	}
+
+	return true;
+}
 
 static void virtnet_get_drvinfo(struct net_device *dev,
 				struct ethtool_drvinfo *info)
@@ -2557,6 +2684,27 @@ static int virtnet_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
 	switch (info->cmd) {
 	case ETHTOOL_GRXRINGS:
 		info->data = vi->curr_queue_pairs;
+		break;
+	case ETHTOOL_GRXFH:
+		virtnet_get_hashflow(vi, info);
+		break;
+	default:
+		rc = -EOPNOTSUPP;
+	}
+
+	return rc;
+}
+
+static int virtnet_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info)
+{
+	struct virtnet_info *vi = netdev_priv(dev);
+	int rc = 0;
+
+	switch (info->cmd) {
+	case ETHTOOL_SRXFH:
+		if (!virtnet_set_hashflow(vi, info))
+			rc = -EINVAL;
+
 		break;
 	default:
 		rc = -EOPNOTSUPP;
@@ -2585,6 +2733,7 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
 	.get_rxfh = virtnet_get_rxfh,
 	.set_rxfh = virtnet_set_rxfh,
 	.get_rxnfc = virtnet_get_rxnfc,
+	.set_rxnfc = virtnet_set_rxnfc,
 };
 
 static void virtnet_freeze_down(struct virtio_device *vdev)
@@ -2837,6 +2986,16 @@ static int virtnet_set_features(struct net_device *dev,
 		vi->guest_offloads = offloads;
 	}
 
+	if ((dev->features ^ features) & NETIF_F_RXHASH) {
+		if (features & NETIF_F_RXHASH)
+			vi->ctrl->rss.table_info.hash_types = vi->rss_hash_types_saved;
+		else
+			vi->ctrl->rss.table_info.hash_types = 0;
+
+		if (!virtnet_commit_rss_command(vi))
+			return -EINVAL;
+	}
+
 	return 0;
 }
 
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [RFC PATCH 3/4] drivers/net/virtio_net: Added basic RSS support.
  2021-10-31  4:59   ` Andrew Melnychenko
  (?)
@ 2021-10-31 15:30   ` kernel test robot
  -1 siblings, 0 replies; 27+ messages in thread
From: kernel test robot @ 2021-10-31 15:30 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 4008 bytes --]

Hi Andrew,

[FYI, it's a private test report for your RFC patch.]
[auto build test ERROR on mst-vhost/linux-next]
[also build test ERROR on net-next/master net/master linus/master v5.15-rc7 next-20211029]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Andrew-Melnychenko/Added-RSS-support/20211031-130048
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost.git linux-next
config: nios2-allyesconfig (attached as .config)
compiler: nios2-linux-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/8bcc65dfaae7855d3748ce0a1b03466a8048540f
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Andrew-Melnychenko/Added-RSS-support/20211031-130048
        git checkout 8bcc65dfaae7855d3748ce0a1b03466a8048540f
        # save the attached .config to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=nios2 SHELL=/bin/bash drivers/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

Note: the linux-review/Andrew-Melnychenko/Added-RSS-support/20211031-130048 HEAD 385fe5b07bf0ded4667d57d48eacf27e3d4e3733 builds fine.
      It only hurts bisectability.

All errors (new ones prefixed by >>):

   drivers/net/virtio_net.c: In function 'virtnet_init_default_rss':
>> drivers/net/virtio_net.c:2260:49: error: 'struct virtnet_info' has no member named 'rss_hash_types_supported'
    2260 |         vi->ctrl->rss.table_info.hash_types = vi->rss_hash_types_supported;
         |                                                 ^~
>> drivers/net/virtio_net.c:2261:11: error: 'struct virtnet_info' has no member named 'rss_hash_types_saved'
    2261 |         vi->rss_hash_types_saved = vi->rss_hash_types_supported;
         |           ^~
   drivers/net/virtio_net.c:2261:38: error: 'struct virtnet_info' has no member named 'rss_hash_types_supported'
    2261 |         vi->rss_hash_types_saved = vi->rss_hash_types_supported;
         |                                      ^~
   drivers/net/virtio_net.c: In function 'virtnet_probe':
   drivers/net/virtio_net.c:3369:19: error: 'struct virtnet_info' has no member named 'rss_hash_types_supported'
    3369 |                 vi->rss_hash_types_supported =
         |                   ^~
   drivers/net/virtio_net.c:3371:19: error: 'struct virtnet_info' has no member named 'rss_hash_types_supported'
    3371 |                 vi->rss_hash_types_supported &=
         |                   ^~


vim +2260 drivers/net/virtio_net.c

  2254	
  2255	static void virtnet_init_default_rss(struct virtnet_info *vi)
  2256	{
  2257		u32 indir_val = 0;
  2258		int i = 0;
  2259	
> 2260		vi->ctrl->rss.table_info.hash_types = vi->rss_hash_types_supported;
> 2261		vi->rss_hash_types_saved = vi->rss_hash_types_supported;
  2262		vi->ctrl->rss.table_info.indirection_table_mask = vi->rss_indir_table_size - 1;
  2263		vi->ctrl->rss.table_info.unclassified_queue = 0;
  2264	
  2265		for (; i < vi->rss_indir_table_size; ++i) {
  2266			indir_val = ethtool_rxfh_indir_default(i, vi->max_queue_pairs);
  2267			vi->ctrl->rss.indirection_table[i] = indir_val;
  2268		}
  2269	
  2270		vi->ctrl->rss.key_info.max_tx_vq = vi->curr_queue_pairs;
  2271		vi->ctrl->rss.key_info.hash_key_length = vi->rss_key_size;
  2272	
  2273		netdev_rss_key_fill(vi->ctrl->rss.key, vi->rss_key_size);
  2274	}
  2275	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 61048 bytes --]

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [RFC PATCH 3/4] drivers/net/virtio_net: Added basic RSS support.
  2021-10-31  4:59   ` Andrew Melnychenko
@ 2021-10-31 15:32     ` Willem de Bruijn
  -1 siblings, 0 replies; 27+ messages in thread
From: Willem de Bruijn @ 2021-10-31 15:32 UTC (permalink / raw)
  To: Andrew Melnychenko
  Cc: mst, jasowang, davem, kuba, virtualization, netdev, linux-kernel,
	yuri.benditovich, yan

On Sun, Oct 31, 2021 at 1:00 AM Andrew Melnychenko <andrew@daynix.com> wrote:
>
> Added features for RSS and RSS hash report.
> Added initialization, RXHASH feature and ethtool ops.
> By default RSS/RXHASH is disabled.
> Added ethtools ops to set key and indirection table.
>
> Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
> ---
>  drivers/net/virtio_net.c | 232 +++++++++++++++++++++++++++++++++++++--
>  1 file changed, 223 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index abca2e93355d..cff7340f40bb 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -167,6 +167,28 @@ struct receive_queue {
>         struct xdp_rxq_info xdp_rxq;
>  };
>
> +/* This structure can contain rss message with maximum settings for indirection table and keysize
> + * Note, that default structure that describes RSS configuration virtio_net_rss_config
> + * contains same info but can't handle table values.
> + * In any case, structure would be passed to virtio hw through sg_buf split by parts
> + * because table sizes may be differ according to the device configuration.
> + */
> +#define VIRTIO_NET_RSS_MAX_KEY_SIZE     40

Unless there is a technical reason, this probably should be no shorter
than TOEPLITZ_KEY_LEN

> +#define VIRTIO_NET_RSS_MAX_TABLE_LEN    128
> +struct virtio_net_ctrl_rss {
> +       struct {
> +               __le32 hash_types;
> +               __le16 indirection_table_mask;
> +               __le16 unclassified_queue;

Is this explicit variable needed?

> +       } __packed table_info;
> +       u16 indirection_table[VIRTIO_NET_RSS_MAX_TABLE_LEN];
> +       struct {
> +               u16 max_tx_vq; /* queues */
> +               u8 hash_key_length;
> +       } __packed key_info;
> +       u8 key[VIRTIO_NET_RSS_MAX_KEY_SIZE];
> +};
> +
>  /* Control VQ buffers: protected by the rtnl lock */
>  struct control_buf {
>         struct virtio_net_ctrl_hdr hdr;
> @@ -176,6 +198,7 @@ struct control_buf {
>         u8 allmulti;
>         __virtio16 vid;
>         __virtio64 offloads;
> +       struct virtio_net_ctrl_rss rss;
>  };
>
>  struct virtnet_info {
> @@ -204,6 +227,12 @@ struct virtnet_info {
>         /* Host will merge rx buffers for big packets (shake it! shake it!) */
>         bool mergeable_rx_bufs;
>
> +       /* Host supports rss and/or hash report */
> +       bool has_rss;

Superfluous, can be derived form non-zero rss_key_size?

> +       bool has_rss_hash_report;
> +       u8 rss_key_size;
> +       u16 rss_indir_table_size;
> +
>         /* Has control virtqueue */
>         bool has_cvq;
>
> @@ -1119,6 +1148,8 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
>         struct net_device *dev = vi->dev;
>         struct sk_buff *skb;
>         struct virtio_net_hdr_mrg_rxbuf *hdr;
> +       struct virtio_net_hdr_v1_hash *hdr_hash;
> +       enum pkt_hash_types rss_hash_type;
>
>         if (unlikely(len < vi->hdr_len + ETH_HLEN)) {
>                 pr_debug("%s: short packet %i\n", dev->name, len);
> @@ -1145,6 +1176,29 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
>                 return;
>
>         hdr = skb_vnet_hdr(skb);
> +       if (vi->has_rss_hash_report && (dev->features & NETIF_F_RXHASH)) {

Only the second test is needed? It should be impossible to configure
the feature unless the device advertises has_rss_hash_report

> +               hdr_hash = (struct virtio_net_hdr_v1_hash *)(hdr);
> +
> +               switch (hdr_hash->hash_report) {
> +               case VIRTIO_NET_HASH_REPORT_TCPv4:
> +               case VIRTIO_NET_HASH_REPORT_UDPv4:
> +               case VIRTIO_NET_HASH_REPORT_TCPv6:
> +               case VIRTIO_NET_HASH_REPORT_UDPv6:
> +               case VIRTIO_NET_HASH_REPORT_TCPv6_EX:
> +               case VIRTIO_NET_HASH_REPORT_UDPv6_EX:
> +                       rss_hash_type = PKT_HASH_TYPE_L4;
> +                       break;
> +               case VIRTIO_NET_HASH_REPORT_IPv4:
> +               case VIRTIO_NET_HASH_REPORT_IPv6:
> +               case VIRTIO_NET_HASH_REPORT_IPv6_EX:
> +                       rss_hash_type = PKT_HASH_TYPE_L3;
> +                       break;
> +               case VIRTIO_NET_HASH_REPORT_NONE:
> +               default:
> +                       rss_hash_type = PKT_HASH_TYPE_NONE;
> +               }

Is this detailed protocol typing necessary? Most devices only pass a bit is_l4.

> +               skb_set_hash(skb, hdr_hash->hash_value, rss_hash_type);
> +       }
>
>         if (hdr->hdr.flags & VIRTIO_NET_HDR_F_DATA_VALID)
>                 skb->ip_summed = CHECKSUM_UNNECESSARY;
> @@ -2167,6 +2221,57 @@ static void virtnet_get_ringparam(struct net_device *dev,
>         ring->tx_pending = ring->tx_max_pending;
>  }
>
> +static bool virtnet_commit_rss_command(struct virtnet_info *vi)
> +{
> +       struct net_device *dev = vi->dev;
> +       struct scatterlist sgs[4];
> +       unsigned int sg_buf_size;
> +
> +       /* prepare sgs */
> +       sg_init_table(sgs, 4);
> +
> +       sg_buf_size = sizeof(vi->ctrl->rss.table_info);
> +       sg_set_buf(&sgs[0], &vi->ctrl->rss.table_info, sg_buf_size);
> +
> +       sg_buf_size = sizeof(uint16_t) * vi->rss_indir_table_size;
> +       sg_set_buf(&sgs[1], vi->ctrl->rss.indirection_table, sg_buf_size);
> +
> +       sg_buf_size = sizeof(vi->ctrl->rss.key_info);
> +       sg_set_buf(&sgs[2], &vi->ctrl->rss.key_info, sg_buf_size);
> +
> +       sg_buf_size = vi->rss_key_size;
> +       sg_set_buf(&sgs[3], vi->ctrl->rss.key, sg_buf_size);
> +
> +       if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MQ,
> +                                 vi->has_rss ? VIRTIO_NET_CTRL_MQ_RSS_CONFIG
> +                                 : VIRTIO_NET_CTRL_MQ_HASH_CONFIG, sgs)) {
> +               dev_warn(&dev->dev, "VIRTIONET issue with committing RSS sgs\n");
> +               return false;
> +       }
> +       return true;
> +}
> +
> +static void virtnet_init_default_rss(struct virtnet_info *vi)
> +{
> +       u32 indir_val = 0;
> +       int i = 0;
> +
> +       vi->ctrl->rss.table_info.hash_types = vi->rss_hash_types_supported;

Similar to above, and related to the next patch: is this very detailed
specification of supported hash types needed? When is this useful? It
is not customary to specify RSS to that degree.

> +       vi->rss_hash_types_saved = vi->rss_hash_types_supported;
> +       vi->ctrl->rss.table_info.indirection_table_mask = vi->rss_indir_table_size - 1;
> +       vi->ctrl->rss.table_info.unclassified_queue = 0;
> +
> +       for (; i < vi->rss_indir_table_size; ++i) {
> +               indir_val = ethtool_rxfh_indir_default(i, vi->max_queue_pairs);
> +               vi->ctrl->rss.indirection_table[i] = indir_val;
> +       }
> +
> +       vi->ctrl->rss.key_info.max_tx_vq = vi->curr_queue_pairs;
> +       vi->ctrl->rss.key_info.hash_key_length = vi->rss_key_size;
> +
> +       netdev_rss_key_fill(vi->ctrl->rss.key, vi->rss_key_size);
> +}
> +
>
>  static void virtnet_get_drvinfo(struct net_device *dev,
>                                 struct ethtool_drvinfo *info)
> @@ -2395,6 +2500,71 @@ static void virtnet_update_settings(struct virtnet_info *vi)
>                 vi->duplex = duplex;
>  }
>
> +static u32 virtnet_get_rxfh_key_size(struct net_device *dev)
> +{
> +       return ((struct virtnet_info *)netdev_priv(dev))->rss_key_size;
> +}
> +
> +static u32 virtnet_get_rxfh_indir_size(struct net_device *dev)
> +{
> +       return ((struct virtnet_info *)netdev_priv(dev))->rss_indir_table_size;
> +}
> +
> +static int virtnet_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc)
> +{
> +       struct virtnet_info *vi = netdev_priv(dev);
> +       int i;
> +
> +       if (indir) {
> +               for (i = 0; i < vi->rss_indir_table_size; ++i)
> +                       indir[i] = vi->ctrl->rss.indirection_table[i];
> +       }
> +
> +       if (key)
> +               memcpy(key, vi->ctrl->rss.key, vi->rss_key_size);
> +
> +       if (hfunc)
> +               *hfunc = ETH_RSS_HASH_TOP;
> +
> +       return 0;
> +}
> +
> +static int virtnet_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key, const u8 hfunc)
> +{
> +       struct virtnet_info *vi = netdev_priv(dev);
> +       int i;
> +
> +       if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
> +               return -EOPNOTSUPP;
> +
> +       if (indir) {
> +               for (i = 0; i < vi->rss_indir_table_size; ++i)
> +                       vi->ctrl->rss.indirection_table[i] = indir[i];
> +       }
> +       if (key)
> +               memcpy(vi->ctrl->rss.key, key, vi->rss_key_size);
> +
> +       virtnet_commit_rss_command(vi);
> +
> +       return 0;
> +}
> +
> +static int virtnet_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, u32 *rule_locs)
> +{
> +       struct virtnet_info *vi = netdev_priv(dev);
> +       int rc = 0;
> +
> +       switch (info->cmd) {
> +       case ETHTOOL_GRXRINGS:
> +               info->data = vi->curr_queue_pairs;
> +               break;
> +       default:
> +               rc = -EOPNOTSUPP;
> +       }
> +
> +       return rc;
> +}
> +
>  static const struct ethtool_ops virtnet_ethtool_ops = {
>         .supported_coalesce_params = ETHTOOL_COALESCE_MAX_FRAMES,
>         .get_drvinfo = virtnet_get_drvinfo,
> @@ -2410,6 +2580,11 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
>         .set_link_ksettings = virtnet_set_link_ksettings,
>         .set_coalesce = virtnet_set_coalesce,
>         .get_coalesce = virtnet_get_coalesce,
> +       .get_rxfh_key_size = virtnet_get_rxfh_key_size,
> +       .get_rxfh_indir_size = virtnet_get_rxfh_indir_size,
> +       .get_rxfh = virtnet_get_rxfh,
> +       .set_rxfh = virtnet_set_rxfh,
> +       .get_rxnfc = virtnet_get_rxnfc,
>  };
>
>  static void virtnet_freeze_down(struct virtio_device *vdev)
> @@ -3040,7 +3215,10 @@ static bool virtnet_validate_features(struct virtio_device *vdev)
>                              "VIRTIO_NET_F_CTRL_VQ") ||
>              VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_MQ, "VIRTIO_NET_F_CTRL_VQ") ||
>              VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR,
> -                            "VIRTIO_NET_F_CTRL_VQ"))) {
> +                            "VIRTIO_NET_F_CTRL_VQ") ||
> +            VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_RSS, "VIRTIO_NET_F_RSS") ||
> +            VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_HASH_REPORT,
> +                            "VIRTIO_NET_F_HASH_REPORT"))) {
>                 return false;
>         }
>
> @@ -3080,13 +3258,14 @@ static int virtnet_probe(struct virtio_device *vdev)
>         u16 max_queue_pairs;
>         int mtu;
>
> -       /* Find if host supports multiqueue virtio_net device */
> -       err = virtio_cread_feature(vdev, VIRTIO_NET_F_MQ,
> -                                  struct virtio_net_config,
> -                                  max_virtqueue_pairs, &max_queue_pairs);
> +       /* Find if host supports multiqueue/rss virtio_net device */
> +       max_queue_pairs = 0;
> +       if (virtio_has_feature(vdev, VIRTIO_NET_F_MQ) || virtio_has_feature(vdev, VIRTIO_NET_F_RSS))

Is VIRTIO_NET_F_RSS implied by VIRTIO_NET_F_MQ?

> +               max_queue_pairs =
> +                    virtio_cread16(vdev, offsetof(struct virtio_net_config, max_virtqueue_pairs));
>
>         /* We need at least 2 queue's */
> -       if (err || max_queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
> +       if (max_queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
>             max_queue_pairs > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX ||
>             !virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
>                 max_queue_pairs = 1;
> @@ -3170,8 +3349,36 @@ static int virtnet_probe(struct virtio_device *vdev)
>         if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
>                 vi->mergeable_rx_bufs = true;
>
> -       if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF) ||
> -           virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
> +       if (virtio_has_feature(vdev, VIRTIO_NET_F_HASH_REPORT)) {
> +               vi->has_rss_hash_report = true;
> +               vi->rss_indir_table_size = 1;
> +               vi->rss_key_size = VIRTIO_NET_RSS_MAX_KEY_SIZE;
> +       }
> +
> +       if (virtio_has_feature(vdev, VIRTIO_NET_F_RSS)) {
> +               vi->has_rss = true;
> +               vi->rss_indir_table_size =
> +                       virtio_cread16(vdev, offsetof(struct virtio_net_config,
> +                                                     rss_max_indirection_table_length));
> +               vi->rss_key_size =
> +                       virtio_cread8(vdev, offsetof(struct virtio_net_config, rss_max_key_size));
> +       }

Please split adding the two features, hash report and rss, into two
separate patches.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [RFC PATCH 3/4] drivers/net/virtio_net: Added basic RSS support.
@ 2021-10-31 15:32     ` Willem de Bruijn
  0 siblings, 0 replies; 27+ messages in thread
From: Willem de Bruijn @ 2021-10-31 15:32 UTC (permalink / raw)
  To: Andrew Melnychenko
  Cc: mst, netdev, linux-kernel, virtualization, yuri.benditovich, yan,
	kuba, davem

On Sun, Oct 31, 2021 at 1:00 AM Andrew Melnychenko <andrew@daynix.com> wrote:
>
> Added features for RSS and RSS hash report.
> Added initialization, RXHASH feature and ethtool ops.
> By default RSS/RXHASH is disabled.
> Added ethtools ops to set key and indirection table.
>
> Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
> ---
>  drivers/net/virtio_net.c | 232 +++++++++++++++++++++++++++++++++++++--
>  1 file changed, 223 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index abca2e93355d..cff7340f40bb 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -167,6 +167,28 @@ struct receive_queue {
>         struct xdp_rxq_info xdp_rxq;
>  };
>
> +/* This structure can contain rss message with maximum settings for indirection table and keysize
> + * Note, that default structure that describes RSS configuration virtio_net_rss_config
> + * contains same info but can't handle table values.
> + * In any case, structure would be passed to virtio hw through sg_buf split by parts
> + * because table sizes may be differ according to the device configuration.
> + */
> +#define VIRTIO_NET_RSS_MAX_KEY_SIZE     40

Unless there is a technical reason, this probably should be no shorter
than TOEPLITZ_KEY_LEN

> +#define VIRTIO_NET_RSS_MAX_TABLE_LEN    128
> +struct virtio_net_ctrl_rss {
> +       struct {
> +               __le32 hash_types;
> +               __le16 indirection_table_mask;
> +               __le16 unclassified_queue;

Is this explicit variable needed?

> +       } __packed table_info;
> +       u16 indirection_table[VIRTIO_NET_RSS_MAX_TABLE_LEN];
> +       struct {
> +               u16 max_tx_vq; /* queues */
> +               u8 hash_key_length;
> +       } __packed key_info;
> +       u8 key[VIRTIO_NET_RSS_MAX_KEY_SIZE];
> +};
> +
>  /* Control VQ buffers: protected by the rtnl lock */
>  struct control_buf {
>         struct virtio_net_ctrl_hdr hdr;
> @@ -176,6 +198,7 @@ struct control_buf {
>         u8 allmulti;
>         __virtio16 vid;
>         __virtio64 offloads;
> +       struct virtio_net_ctrl_rss rss;
>  };
>
>  struct virtnet_info {
> @@ -204,6 +227,12 @@ struct virtnet_info {
>         /* Host will merge rx buffers for big packets (shake it! shake it!) */
>         bool mergeable_rx_bufs;
>
> +       /* Host supports rss and/or hash report */
> +       bool has_rss;

Superfluous, can be derived form non-zero rss_key_size?

> +       bool has_rss_hash_report;
> +       u8 rss_key_size;
> +       u16 rss_indir_table_size;
> +
>         /* Has control virtqueue */
>         bool has_cvq;
>
> @@ -1119,6 +1148,8 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
>         struct net_device *dev = vi->dev;
>         struct sk_buff *skb;
>         struct virtio_net_hdr_mrg_rxbuf *hdr;
> +       struct virtio_net_hdr_v1_hash *hdr_hash;
> +       enum pkt_hash_types rss_hash_type;
>
>         if (unlikely(len < vi->hdr_len + ETH_HLEN)) {
>                 pr_debug("%s: short packet %i\n", dev->name, len);
> @@ -1145,6 +1176,29 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
>                 return;
>
>         hdr = skb_vnet_hdr(skb);
> +       if (vi->has_rss_hash_report && (dev->features & NETIF_F_RXHASH)) {

Only the second test is needed? It should be impossible to configure
the feature unless the device advertises has_rss_hash_report

> +               hdr_hash = (struct virtio_net_hdr_v1_hash *)(hdr);
> +
> +               switch (hdr_hash->hash_report) {
> +               case VIRTIO_NET_HASH_REPORT_TCPv4:
> +               case VIRTIO_NET_HASH_REPORT_UDPv4:
> +               case VIRTIO_NET_HASH_REPORT_TCPv6:
> +               case VIRTIO_NET_HASH_REPORT_UDPv6:
> +               case VIRTIO_NET_HASH_REPORT_TCPv6_EX:
> +               case VIRTIO_NET_HASH_REPORT_UDPv6_EX:
> +                       rss_hash_type = PKT_HASH_TYPE_L4;
> +                       break;
> +               case VIRTIO_NET_HASH_REPORT_IPv4:
> +               case VIRTIO_NET_HASH_REPORT_IPv6:
> +               case VIRTIO_NET_HASH_REPORT_IPv6_EX:
> +                       rss_hash_type = PKT_HASH_TYPE_L3;
> +                       break;
> +               case VIRTIO_NET_HASH_REPORT_NONE:
> +               default:
> +                       rss_hash_type = PKT_HASH_TYPE_NONE;
> +               }

Is this detailed protocol typing necessary? Most devices only pass a bit is_l4.

> +               skb_set_hash(skb, hdr_hash->hash_value, rss_hash_type);
> +       }
>
>         if (hdr->hdr.flags & VIRTIO_NET_HDR_F_DATA_VALID)
>                 skb->ip_summed = CHECKSUM_UNNECESSARY;
> @@ -2167,6 +2221,57 @@ static void virtnet_get_ringparam(struct net_device *dev,
>         ring->tx_pending = ring->tx_max_pending;
>  }
>
> +static bool virtnet_commit_rss_command(struct virtnet_info *vi)
> +{
> +       struct net_device *dev = vi->dev;
> +       struct scatterlist sgs[4];
> +       unsigned int sg_buf_size;
> +
> +       /* prepare sgs */
> +       sg_init_table(sgs, 4);
> +
> +       sg_buf_size = sizeof(vi->ctrl->rss.table_info);
> +       sg_set_buf(&sgs[0], &vi->ctrl->rss.table_info, sg_buf_size);
> +
> +       sg_buf_size = sizeof(uint16_t) * vi->rss_indir_table_size;
> +       sg_set_buf(&sgs[1], vi->ctrl->rss.indirection_table, sg_buf_size);
> +
> +       sg_buf_size = sizeof(vi->ctrl->rss.key_info);
> +       sg_set_buf(&sgs[2], &vi->ctrl->rss.key_info, sg_buf_size);
> +
> +       sg_buf_size = vi->rss_key_size;
> +       sg_set_buf(&sgs[3], vi->ctrl->rss.key, sg_buf_size);
> +
> +       if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MQ,
> +                                 vi->has_rss ? VIRTIO_NET_CTRL_MQ_RSS_CONFIG
> +                                 : VIRTIO_NET_CTRL_MQ_HASH_CONFIG, sgs)) {
> +               dev_warn(&dev->dev, "VIRTIONET issue with committing RSS sgs\n");
> +               return false;
> +       }
> +       return true;
> +}
> +
> +static void virtnet_init_default_rss(struct virtnet_info *vi)
> +{
> +       u32 indir_val = 0;
> +       int i = 0;
> +
> +       vi->ctrl->rss.table_info.hash_types = vi->rss_hash_types_supported;

Similar to above, and related to the next patch: is this very detailed
specification of supported hash types needed? When is this useful? It
is not customary to specify RSS to that degree.

> +       vi->rss_hash_types_saved = vi->rss_hash_types_supported;
> +       vi->ctrl->rss.table_info.indirection_table_mask = vi->rss_indir_table_size - 1;
> +       vi->ctrl->rss.table_info.unclassified_queue = 0;
> +
> +       for (; i < vi->rss_indir_table_size; ++i) {
> +               indir_val = ethtool_rxfh_indir_default(i, vi->max_queue_pairs);
> +               vi->ctrl->rss.indirection_table[i] = indir_val;
> +       }
> +
> +       vi->ctrl->rss.key_info.max_tx_vq = vi->curr_queue_pairs;
> +       vi->ctrl->rss.key_info.hash_key_length = vi->rss_key_size;
> +
> +       netdev_rss_key_fill(vi->ctrl->rss.key, vi->rss_key_size);
> +}
> +
>
>  static void virtnet_get_drvinfo(struct net_device *dev,
>                                 struct ethtool_drvinfo *info)
> @@ -2395,6 +2500,71 @@ static void virtnet_update_settings(struct virtnet_info *vi)
>                 vi->duplex = duplex;
>  }
>
> +static u32 virtnet_get_rxfh_key_size(struct net_device *dev)
> +{
> +       return ((struct virtnet_info *)netdev_priv(dev))->rss_key_size;
> +}
> +
> +static u32 virtnet_get_rxfh_indir_size(struct net_device *dev)
> +{
> +       return ((struct virtnet_info *)netdev_priv(dev))->rss_indir_table_size;
> +}
> +
> +static int virtnet_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc)
> +{
> +       struct virtnet_info *vi = netdev_priv(dev);
> +       int i;
> +
> +       if (indir) {
> +               for (i = 0; i < vi->rss_indir_table_size; ++i)
> +                       indir[i] = vi->ctrl->rss.indirection_table[i];
> +       }
> +
> +       if (key)
> +               memcpy(key, vi->ctrl->rss.key, vi->rss_key_size);
> +
> +       if (hfunc)
> +               *hfunc = ETH_RSS_HASH_TOP;
> +
> +       return 0;
> +}
> +
> +static int virtnet_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key, const u8 hfunc)
> +{
> +       struct virtnet_info *vi = netdev_priv(dev);
> +       int i;
> +
> +       if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
> +               return -EOPNOTSUPP;
> +
> +       if (indir) {
> +               for (i = 0; i < vi->rss_indir_table_size; ++i)
> +                       vi->ctrl->rss.indirection_table[i] = indir[i];
> +       }
> +       if (key)
> +               memcpy(vi->ctrl->rss.key, key, vi->rss_key_size);
> +
> +       virtnet_commit_rss_command(vi);
> +
> +       return 0;
> +}
> +
> +static int virtnet_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, u32 *rule_locs)
> +{
> +       struct virtnet_info *vi = netdev_priv(dev);
> +       int rc = 0;
> +
> +       switch (info->cmd) {
> +       case ETHTOOL_GRXRINGS:
> +               info->data = vi->curr_queue_pairs;
> +               break;
> +       default:
> +               rc = -EOPNOTSUPP;
> +       }
> +
> +       return rc;
> +}
> +
>  static const struct ethtool_ops virtnet_ethtool_ops = {
>         .supported_coalesce_params = ETHTOOL_COALESCE_MAX_FRAMES,
>         .get_drvinfo = virtnet_get_drvinfo,
> @@ -2410,6 +2580,11 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
>         .set_link_ksettings = virtnet_set_link_ksettings,
>         .set_coalesce = virtnet_set_coalesce,
>         .get_coalesce = virtnet_get_coalesce,
> +       .get_rxfh_key_size = virtnet_get_rxfh_key_size,
> +       .get_rxfh_indir_size = virtnet_get_rxfh_indir_size,
> +       .get_rxfh = virtnet_get_rxfh,
> +       .set_rxfh = virtnet_set_rxfh,
> +       .get_rxnfc = virtnet_get_rxnfc,
>  };
>
>  static void virtnet_freeze_down(struct virtio_device *vdev)
> @@ -3040,7 +3215,10 @@ static bool virtnet_validate_features(struct virtio_device *vdev)
>                              "VIRTIO_NET_F_CTRL_VQ") ||
>              VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_MQ, "VIRTIO_NET_F_CTRL_VQ") ||
>              VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR,
> -                            "VIRTIO_NET_F_CTRL_VQ"))) {
> +                            "VIRTIO_NET_F_CTRL_VQ") ||
> +            VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_RSS, "VIRTIO_NET_F_RSS") ||
> +            VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_HASH_REPORT,
> +                            "VIRTIO_NET_F_HASH_REPORT"))) {
>                 return false;
>         }
>
> @@ -3080,13 +3258,14 @@ static int virtnet_probe(struct virtio_device *vdev)
>         u16 max_queue_pairs;
>         int mtu;
>
> -       /* Find if host supports multiqueue virtio_net device */
> -       err = virtio_cread_feature(vdev, VIRTIO_NET_F_MQ,
> -                                  struct virtio_net_config,
> -                                  max_virtqueue_pairs, &max_queue_pairs);
> +       /* Find if host supports multiqueue/rss virtio_net device */
> +       max_queue_pairs = 0;
> +       if (virtio_has_feature(vdev, VIRTIO_NET_F_MQ) || virtio_has_feature(vdev, VIRTIO_NET_F_RSS))

Is VIRTIO_NET_F_RSS implied by VIRTIO_NET_F_MQ?

> +               max_queue_pairs =
> +                    virtio_cread16(vdev, offsetof(struct virtio_net_config, max_virtqueue_pairs));
>
>         /* We need at least 2 queue's */
> -       if (err || max_queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
> +       if (max_queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
>             max_queue_pairs > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX ||
>             !virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
>                 max_queue_pairs = 1;
> @@ -3170,8 +3349,36 @@ static int virtnet_probe(struct virtio_device *vdev)
>         if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
>                 vi->mergeable_rx_bufs = true;
>
> -       if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF) ||
> -           virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
> +       if (virtio_has_feature(vdev, VIRTIO_NET_F_HASH_REPORT)) {
> +               vi->has_rss_hash_report = true;
> +               vi->rss_indir_table_size = 1;
> +               vi->rss_key_size = VIRTIO_NET_RSS_MAX_KEY_SIZE;
> +       }
> +
> +       if (virtio_has_feature(vdev, VIRTIO_NET_F_RSS)) {
> +               vi->has_rss = true;
> +               vi->rss_indir_table_size =
> +                       virtio_cread16(vdev, offsetof(struct virtio_net_config,
> +                                                     rss_max_indirection_table_length));
> +               vi->rss_key_size =
> +                       virtio_cread8(vdev, offsetof(struct virtio_net_config, rss_max_key_size));
> +       }

Please split adding the two features, hash report and rss, into two
separate patches.
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [RFC PATCH 3/4] drivers/net/virtio_net: Added basic RSS support.
  2021-10-31 15:32     ` Willem de Bruijn
@ 2021-10-31 15:37       ` Willem de Bruijn
  -1 siblings, 0 replies; 27+ messages in thread
From: Willem de Bruijn @ 2021-10-31 15:37 UTC (permalink / raw)
  To: Willem de Bruijn
  Cc: Andrew Melnychenko, mst, jasowang, davem, kuba, virtualization,
	netdev, linux-kernel, yuri.benditovich, yan

> > +               hdr_hash = (struct virtio_net_hdr_v1_hash *)(hdr);
> > +
> > +               switch (hdr_hash->hash_report) {
> > +               case VIRTIO_NET_HASH_REPORT_TCPv4:
> > +               case VIRTIO_NET_HASH_REPORT_UDPv4:
> > +               case VIRTIO_NET_HASH_REPORT_TCPv6:
> > +               case VIRTIO_NET_HASH_REPORT_UDPv6:
> > +               case VIRTIO_NET_HASH_REPORT_TCPv6_EX:
> > +               case VIRTIO_NET_HASH_REPORT_UDPv6_EX:
> > +                       rss_hash_type = PKT_HASH_TYPE_L4;
> > +                       break;
> > +               case VIRTIO_NET_HASH_REPORT_IPv4:
> > +               case VIRTIO_NET_HASH_REPORT_IPv6:
> > +               case VIRTIO_NET_HASH_REPORT_IPv6_EX:
> > +                       rss_hash_type = PKT_HASH_TYPE_L3;
> > +                       break;
> > +               case VIRTIO_NET_HASH_REPORT_NONE:
> > +               default:
> > +                       rss_hash_type = PKT_HASH_TYPE_NONE;
> > +               }
>
> Is this detailed protocol typing necessary? Most devices only pass a bit is_l4.
> > +static void virtnet_init_default_rss(struct virtnet_info *vi)
> > +{
> > +       u32 indir_val = 0;
> > +       int i = 0;
> > +
> > +       vi->ctrl->rss.table_info.hash_types = vi->rss_hash_types_supported;
>
> Similar to above, and related to the next patch: is this very detailed
> specification of supported hash types needed? When is this useful? It
> is not customary to specify RSS to that degree.

My bad. This is also implemented by bnxt, for one. I was unaware of
this feature.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [RFC PATCH 3/4] drivers/net/virtio_net: Added basic RSS support.
@ 2021-10-31 15:37       ` Willem de Bruijn
  0 siblings, 0 replies; 27+ messages in thread
From: Willem de Bruijn @ 2021-10-31 15:37 UTC (permalink / raw)
  To: Willem de Bruijn
  Cc: Andrew Melnychenko, mst, netdev, linux-kernel, virtualization,
	yuri.benditovich, yan, kuba, davem

> > +               hdr_hash = (struct virtio_net_hdr_v1_hash *)(hdr);
> > +
> > +               switch (hdr_hash->hash_report) {
> > +               case VIRTIO_NET_HASH_REPORT_TCPv4:
> > +               case VIRTIO_NET_HASH_REPORT_UDPv4:
> > +               case VIRTIO_NET_HASH_REPORT_TCPv6:
> > +               case VIRTIO_NET_HASH_REPORT_UDPv6:
> > +               case VIRTIO_NET_HASH_REPORT_TCPv6_EX:
> > +               case VIRTIO_NET_HASH_REPORT_UDPv6_EX:
> > +                       rss_hash_type = PKT_HASH_TYPE_L4;
> > +                       break;
> > +               case VIRTIO_NET_HASH_REPORT_IPv4:
> > +               case VIRTIO_NET_HASH_REPORT_IPv6:
> > +               case VIRTIO_NET_HASH_REPORT_IPv6_EX:
> > +                       rss_hash_type = PKT_HASH_TYPE_L3;
> > +                       break;
> > +               case VIRTIO_NET_HASH_REPORT_NONE:
> > +               default:
> > +                       rss_hash_type = PKT_HASH_TYPE_NONE;
> > +               }
>
> Is this detailed protocol typing necessary? Most devices only pass a bit is_l4.
> > +static void virtnet_init_default_rss(struct virtnet_info *vi)
> > +{
> > +       u32 indir_val = 0;
> > +       int i = 0;
> > +
> > +       vi->ctrl->rss.table_info.hash_types = vi->rss_hash_types_supported;
>
> Similar to above, and related to the next patch: is this very detailed
> specification of supported hash types needed? When is this useful? It
> is not customary to specify RSS to that degree.

My bad. This is also implemented by bnxt, for one. I was unaware of
this feature.
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [RFC PATCH 2/4] drivers/net/virtio_net: Changed mergeable buffer length calculation.
  2021-10-31  4:59   ` Andrew Melnychenko
  (?)
@ 2021-10-31 16:11   ` kernel test robot
  -1 siblings, 0 replies; 27+ messages in thread
From: kernel test robot @ 2021-10-31 16:11 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 6339 bytes --]

Hi Andrew,

[FYI, it's a private test report for your RFC patch.]
[auto build test ERROR on mst-vhost/linux-next]
[also build test ERROR on net-next/master net/master linus/master v5.15-rc7 next-20211029]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Andrew-Melnychenko/Added-RSS-support/20211031-130048
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost.git linux-next
config: riscv-allyesconfig (attached as .config)
compiler: riscv64-linux-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/ca643e21484393b5386b7b86542c3ebb37445a70
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Andrew-Melnychenko/Added-RSS-support/20211031-130048
        git checkout ca643e21484393b5386b7b86542c3ebb37445a70
        # save the attached .config to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=riscv SHELL=/bin/bash drivers/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

Note: the linux-review/Andrew-Melnychenko/Added-RSS-support/20211031-130048 HEAD 385fe5b07bf0ded4667d57d48eacf27e3d4e3733 builds fine.
      It only hurts bisectability.

All errors (new ones prefixed by >>):

   drivers/net/virtio_net.c: In function 'page_to_skb':
>> drivers/net/virtio_net.c:396:15: error: 'struct virtnet_info' has no member named 'has_rss_hash_report'
     396 |         if (vi->has_rss_hash_report)
         |               ^~


vim +396 drivers/net/virtio_net.c

   376	
   377	/* Called from bottom half context */
   378	static struct sk_buff *page_to_skb(struct virtnet_info *vi,
   379					   struct receive_queue *rq,
   380					   struct page *page, unsigned int offset,
   381					   unsigned int len, unsigned int truesize,
   382					   bool hdr_valid, unsigned int metasize,
   383					   unsigned int headroom)
   384	{
   385		struct sk_buff *skb;
   386		struct virtio_net_hdr_mrg_rxbuf *hdr;
   387		unsigned int copy, hdr_len, hdr_padded_len;
   388		struct page *page_to_free = NULL;
   389		int tailroom, shinfo_size;
   390		char *p, *hdr_p, *buf;
   391	
   392		p = page_address(page) + offset;
   393		hdr_p = p;
   394	
   395		hdr_len = vi->hdr_len;
 > 396		if (vi->has_rss_hash_report)
   397			hdr_padded_len = sizeof(struct virtio_net_hdr_v1_hash);
   398		else if (vi->mergeable_rx_bufs)
   399			hdr_padded_len = sizeof(*hdr);
   400		else
   401			hdr_padded_len = sizeof(struct padded_vnet_hdr);
   402	
   403		/* If headroom is not 0, there is an offset between the beginning of the
   404		 * data and the allocated space, otherwise the data and the allocated
   405		 * space are aligned.
   406		 *
   407		 * Buffers with headroom use PAGE_SIZE as alloc size, see
   408		 * add_recvbuf_mergeable() + get_mergeable_buf_len()
   409		 */
   410		truesize = headroom ? PAGE_SIZE : truesize;
   411		tailroom = truesize - headroom;
   412		buf = p - headroom;
   413	
   414		len -= hdr_len;
   415		offset += hdr_padded_len;
   416		p += hdr_padded_len;
   417		tailroom -= hdr_padded_len + len;
   418	
   419		shinfo_size = SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
   420	
   421		/* copy small packet so we can reuse these pages */
   422		if (!NET_IP_ALIGN && len > GOOD_COPY_LEN && tailroom >= shinfo_size) {
   423			skb = build_skb(buf, truesize);
   424			if (unlikely(!skb))
   425				return NULL;
   426	
   427			skb_reserve(skb, p - buf);
   428			skb_put(skb, len);
   429	
   430			page = (struct page *)page->private;
   431			if (page)
   432				give_pages(rq, page);
   433			goto ok;
   434		}
   435	
   436		/* copy small packet so we can reuse these pages for small data */
   437		skb = napi_alloc_skb(&rq->napi, GOOD_COPY_LEN);
   438		if (unlikely(!skb))
   439			return NULL;
   440	
   441		/* Copy all frame if it fits skb->head, otherwise
   442		 * we let virtio_net_hdr_to_skb() and GRO pull headers as needed.
   443		 */
   444		if (len <= skb_tailroom(skb))
   445			copy = len;
   446		else
   447			copy = ETH_HLEN + metasize;
   448		skb_put_data(skb, p, copy);
   449	
   450		len -= copy;
   451		offset += copy;
   452	
   453		if (vi->mergeable_rx_bufs) {
   454			if (len)
   455				skb_add_rx_frag(skb, 0, page, offset, len, truesize);
   456			else
   457				page_to_free = page;
   458			goto ok;
   459		}
   460	
   461		/*
   462		 * Verify that we can indeed put this data into a skb.
   463		 * This is here to handle cases when the device erroneously
   464		 * tries to receive more than is possible. This is usually
   465		 * the case of a broken device.
   466		 */
   467		if (unlikely(len > MAX_SKB_FRAGS * PAGE_SIZE)) {
   468			net_dbg_ratelimited("%s: too much data\n", skb->dev->name);
   469			dev_kfree_skb(skb);
   470			return NULL;
   471		}
   472		BUG_ON(offset >= PAGE_SIZE);
   473		while (len) {
   474			unsigned int frag_size = min((unsigned)PAGE_SIZE - offset, len);
   475			skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, offset,
   476					frag_size, truesize);
   477			len -= frag_size;
   478			page = (struct page *)page->private;
   479			offset = 0;
   480		}
   481	
   482		if (page)
   483			give_pages(rq, page);
   484	
   485	ok:
   486		/* hdr_valid means no XDP, so we can copy the vnet header */
   487		if (hdr_valid) {
   488			hdr = skb_vnet_hdr(skb);
   489			memcpy(hdr, hdr_p, hdr_len);
   490		}
   491		if (page_to_free)
   492			put_page(page_to_free);
   493	
   494		if (metasize) {
   495			__skb_pull(skb, metasize);
   496			skb_metadata_set(skb, metasize);
   497		}
   498	
   499		return skb;
   500	}
   501	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 71110 bytes --]

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [RFC PATCH 1/4] drivers/net/virtio_net: Fixed vheader to use v1.
  2021-10-31  4:59   ` Andrew Melnychenko
@ 2021-11-01  8:40     ` Michael S. Tsirkin
  -1 siblings, 0 replies; 27+ messages in thread
From: Michael S. Tsirkin @ 2021-11-01  8:40 UTC (permalink / raw)
  To: Andrew Melnychenko
  Cc: jasowang, davem, kuba, virtualization, netdev, linux-kernel,
	yuri.benditovich, yan

On Sun, Oct 31, 2021 at 06:59:56AM +0200, Andrew Melnychenko wrote:
> The header v1 provides additional info about RSS.
> Added changes to computing proper header length.
> In the next patches, the header may contain RSS hash info
> for the hash population.
> 
> Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
> ---
>  drivers/net/virtio_net.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index 4ad25a8b0870..b72b21ac8ebd 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -240,13 +240,13 @@ struct virtnet_info {
>  };
>  
>  struct padded_vnet_hdr {
> -	struct virtio_net_hdr_mrg_rxbuf hdr;
> +	struct virtio_net_hdr_v1_hash hdr;
>  	/*
>  	 * hdr is in a separate sg buffer, and data sg buffer shares same page
>  	 * with this header sg. This padding makes next sg 16 byte aligned
>  	 * after the header.
>  	 */
> -	char padding[4];
> +	char padding[12];
>  };
>  
>  static bool is_xdp_frame(void *ptr)


This is not helpful as a separate patch, just reserving extra space.
better squash with the patches making use of the change.

> @@ -1636,7 +1636,7 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
>  	const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
>  	struct virtnet_info *vi = sq->vq->vdev->priv;
>  	int num_sg;
> -	unsigned hdr_len = vi->hdr_len;
> +	unsigned int hdr_len = vi->hdr_len;
>  	bool can_push;


if we want this, pls make it a separate patch.


>  
>  	pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest);
> -- 
> 2.33.1


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [RFC PATCH 1/4] drivers/net/virtio_net: Fixed vheader to use v1.
@ 2021-11-01  8:40     ` Michael S. Tsirkin
  0 siblings, 0 replies; 27+ messages in thread
From: Michael S. Tsirkin @ 2021-11-01  8:40 UTC (permalink / raw)
  To: Andrew Melnychenko
  Cc: netdev, linux-kernel, virtualization, yuri.benditovich, yan, kuba, davem

On Sun, Oct 31, 2021 at 06:59:56AM +0200, Andrew Melnychenko wrote:
> The header v1 provides additional info about RSS.
> Added changes to computing proper header length.
> In the next patches, the header may contain RSS hash info
> for the hash population.
> 
> Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
> ---
>  drivers/net/virtio_net.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index 4ad25a8b0870..b72b21ac8ebd 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -240,13 +240,13 @@ struct virtnet_info {
>  };
>  
>  struct padded_vnet_hdr {
> -	struct virtio_net_hdr_mrg_rxbuf hdr;
> +	struct virtio_net_hdr_v1_hash hdr;
>  	/*
>  	 * hdr is in a separate sg buffer, and data sg buffer shares same page
>  	 * with this header sg. This padding makes next sg 16 byte aligned
>  	 * after the header.
>  	 */
> -	char padding[4];
> +	char padding[12];
>  };
>  
>  static bool is_xdp_frame(void *ptr)


This is not helpful as a separate patch, just reserving extra space.
better squash with the patches making use of the change.

> @@ -1636,7 +1636,7 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
>  	const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
>  	struct virtnet_info *vi = sq->vq->vdev->priv;
>  	int num_sg;
> -	unsigned hdr_len = vi->hdr_len;
> +	unsigned int hdr_len = vi->hdr_len;
>  	bool can_push;


if we want this, pls make it a separate patch.


>  
>  	pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest);
> -- 
> 2.33.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [RFC PATCH 2/4] drivers/net/virtio_net: Changed mergeable buffer length calculation.
  2021-10-31  4:59   ` Andrew Melnychenko
@ 2021-11-01  8:44     ` Michael S. Tsirkin
  -1 siblings, 0 replies; 27+ messages in thread
From: Michael S. Tsirkin @ 2021-11-01  8:44 UTC (permalink / raw)
  To: Andrew Melnychenko
  Cc: jasowang, davem, kuba, virtualization, netdev, linux-kernel,
	yuri.benditovich, yan

On Sun, Oct 31, 2021 at 06:59:57AM +0200, Andrew Melnychenko wrote:
> Now minimal virtual header length is may include the entire v1 header
> if the hash report were populated.
> 
> Signed-off-by: Andrew Melnychenko <andrew@daynix.com>

subject isn't really descriptive. changed it how?

And I couldn't really decypher what this log entry means either.

> ---
>  drivers/net/virtio_net.c | 8 +++++---
>  1 file changed, 5 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index b72b21ac8ebd..abca2e93355d 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -393,7 +393,9 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
>  	hdr_p = p;
>  
>  	hdr_len = vi->hdr_len;
> -	if (vi->mergeable_rx_bufs)
> +	if (vi->has_rss_hash_report)
> +		hdr_padded_len = sizeof(struct virtio_net_hdr_v1_hash);
> +	else if (vi->mergeable_rx_bufs)
>  		hdr_padded_len = sizeof(*hdr);
>  	else
>  		hdr_padded_len = sizeof(struct padded_vnet_hdr);
> @@ -1252,7 +1254,7 @@ static unsigned int get_mergeable_buf_len(struct receive_queue *rq,
>  					  struct ewma_pkt_len *avg_pkt_len,
>  					  unsigned int room)
>  {
> -	const size_t hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
> +	const size_t hdr_len = ((struct virtnet_info *)(rq->vq->vdev->priv))->hdr_len;
>  	unsigned int len;
>  
>  	if (room)

Is this pointer chasing the best we can do?

> @@ -2817,7 +2819,7 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
>   */
>  static unsigned int mergeable_min_buf_len(struct virtnet_info *vi, struct virtqueue *vq)
>  {
> -	const unsigned int hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
> +	const unsigned int hdr_len = vi->hdr_len;
>  	unsigned int rq_size = virtqueue_get_vring_size(vq);
>  	unsigned int packet_len = vi->big_packets ? IP_MAX_MTU : vi->dev->max_mtu;
>  	unsigned int buf_len = hdr_len + ETH_HLEN + VLAN_HLEN + packet_len;
> -- 
> 2.33.1


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [RFC PATCH 2/4] drivers/net/virtio_net: Changed mergeable buffer length calculation.
@ 2021-11-01  8:44     ` Michael S. Tsirkin
  0 siblings, 0 replies; 27+ messages in thread
From: Michael S. Tsirkin @ 2021-11-01  8:44 UTC (permalink / raw)
  To: Andrew Melnychenko
  Cc: netdev, linux-kernel, virtualization, yuri.benditovich, yan, kuba, davem

On Sun, Oct 31, 2021 at 06:59:57AM +0200, Andrew Melnychenko wrote:
> Now minimal virtual header length is may include the entire v1 header
> if the hash report were populated.
> 
> Signed-off-by: Andrew Melnychenko <andrew@daynix.com>

subject isn't really descriptive. changed it how?

And I couldn't really decypher what this log entry means either.

> ---
>  drivers/net/virtio_net.c | 8 +++++---
>  1 file changed, 5 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index b72b21ac8ebd..abca2e93355d 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -393,7 +393,9 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
>  	hdr_p = p;
>  
>  	hdr_len = vi->hdr_len;
> -	if (vi->mergeable_rx_bufs)
> +	if (vi->has_rss_hash_report)
> +		hdr_padded_len = sizeof(struct virtio_net_hdr_v1_hash);
> +	else if (vi->mergeable_rx_bufs)
>  		hdr_padded_len = sizeof(*hdr);
>  	else
>  		hdr_padded_len = sizeof(struct padded_vnet_hdr);
> @@ -1252,7 +1254,7 @@ static unsigned int get_mergeable_buf_len(struct receive_queue *rq,
>  					  struct ewma_pkt_len *avg_pkt_len,
>  					  unsigned int room)
>  {
> -	const size_t hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
> +	const size_t hdr_len = ((struct virtnet_info *)(rq->vq->vdev->priv))->hdr_len;
>  	unsigned int len;
>  
>  	if (room)

Is this pointer chasing the best we can do?

> @@ -2817,7 +2819,7 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
>   */
>  static unsigned int mergeable_min_buf_len(struct virtnet_info *vi, struct virtqueue *vq)
>  {
> -	const unsigned int hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
> +	const unsigned int hdr_len = vi->hdr_len;
>  	unsigned int rq_size = virtqueue_get_vring_size(vq);
>  	unsigned int packet_len = vi->big_packets ? IP_MAX_MTU : vi->dev->max_mtu;
>  	unsigned int buf_len = hdr_len + ETH_HLEN + VLAN_HLEN + packet_len;
> -- 
> 2.33.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [RFC PATCH 4/4] drivers/net/virtio_net: Added RSS hash report control.
  2021-10-31  4:59   ` Andrew Melnychenko
  (?)
@ 2021-11-01 19:49   ` kernel test robot
  -1 siblings, 0 replies; 27+ messages in thread
From: kernel test robot @ 2021-11-01 19:49 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 11642 bytes --]

Hi Andrew,

[FYI, it's a private test report for your RFC patch.]
[auto build test WARNING on mst-vhost/linux-next]
[also build test WARNING on net-next/master net/master v5.15 next-20211101]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Andrew-Melnychenko/Added-RSS-support/20211031-130048
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost.git linux-next
config: x86_64-randconfig-s021-20211101 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
reproduce:
        # apt-get install sparse
        # sparse version: v0.6.4-dirty
        # https://github.com/0day-ci/linux/commit/385fe5b07bf0ded4667d57d48eacf27e3d4e3733
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Andrew-Melnychenko/Added-RSS-support/20211031-130048
        git checkout 385fe5b07bf0ded4667d57d48eacf27e3d4e3733
        # save the attached .config to linux build tree
        make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=x86_64 SHELL=/bin/bash drivers/net/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>


sparse warnings: (new ones prefixed by >>)
>> drivers/net/virtio_net.c:1185:33: sparse: sparse: restricted __le16 degrades to integer
>> drivers/net/virtio_net.c:1185:33: sparse: sparse: restricted __le16 degrades to integer
>> drivers/net/virtio_net.c:1185:33: sparse: sparse: restricted __le16 degrades to integer
>> drivers/net/virtio_net.c:1185:33: sparse: sparse: restricted __le16 degrades to integer
>> drivers/net/virtio_net.c:1185:33: sparse: sparse: restricted __le16 degrades to integer
>> drivers/net/virtio_net.c:1185:33: sparse: sparse: restricted __le16 degrades to integer
>> drivers/net/virtio_net.c:1185:33: sparse: sparse: restricted __le16 degrades to integer
>> drivers/net/virtio_net.c:1185:33: sparse: sparse: restricted __le16 degrades to integer
>> drivers/net/virtio_net.c:1185:33: sparse: sparse: restricted __le16 degrades to integer
>> drivers/net/virtio_net.c:1203:43: sparse: sparse: incorrect type in argument 2 (different base types) @@     expected unsigned int [usertype] hash @@     got restricted __le32 [usertype] hash_value @@
   drivers/net/virtio_net.c:1203:43: sparse:     expected unsigned int [usertype] hash
   drivers/net/virtio_net.c:1203:43: sparse:     got restricted __le32 [usertype] hash_value
>> drivers/net/virtio_net.c:2262:45: sparse: sparse: incorrect type in assignment (different base types) @@     expected restricted __le32 [usertype] hash_types @@     got unsigned int [usertype] rss_hash_types_supported @@
   drivers/net/virtio_net.c:2262:45: sparse:     expected restricted __le32 [usertype] hash_types
   drivers/net/virtio_net.c:2262:45: sparse:     got unsigned int [usertype] rss_hash_types_supported
>> drivers/net/virtio_net.c:2264:57: sparse: sparse: incorrect type in assignment (different base types) @@     expected restricted __le16 [usertype] indirection_table_mask @@     got int @@
   drivers/net/virtio_net.c:2264:57: sparse:     expected restricted __le16 [usertype] indirection_table_mask
   drivers/net/virtio_net.c:2264:57: sparse:     got int
>> drivers/net/virtio_net.c:2396:53: sparse: sparse: incorrect type in assignment (different base types) @@     expected restricted __le32 [usertype] hash_types @@     got unsigned int [usertype] rss_hash_types_saved @@
   drivers/net/virtio_net.c:2396:53: sparse:     expected restricted __le32 [usertype] hash_types
   drivers/net/virtio_net.c:2396:53: sparse:     got unsigned int [usertype] rss_hash_types_saved
   drivers/net/virtio_net.c:2992:61: sparse: sparse: incorrect type in assignment (different base types) @@     expected restricted __le32 [usertype] hash_types @@     got unsigned int [usertype] rss_hash_types_saved @@
   drivers/net/virtio_net.c:2992:61: sparse:     expected restricted __le32 [usertype] hash_types
   drivers/net/virtio_net.c:2992:61: sparse:     got unsigned int [usertype] rss_hash_types_saved

vim +1185 drivers/net/virtio_net.c

23cde76d801246 Mark McLoughlin        2008-06-08  1145  
7d9d60fd4ab696 Toshiaki Makita        2018-07-23  1146  static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
2471c75efed325 Jesper Dangaard Brouer 2018-06-26  1147  			void *buf, unsigned int len, void **ctx,
a0929a44c2065d Toshiaki Makita        2018-07-23  1148  			unsigned int *xdp_xmit,
d46eeeaf99bcfa Jason Wang             2018-07-31  1149  			struct virtnet_rq_stats *stats)
9ab86bbcf8be75 Shirley Ma             2010-01-29  1150  {
e9d7417b97f420 Jason Wang             2012-12-07  1151  	struct net_device *dev = vi->dev;
9ab86bbcf8be75 Shirley Ma             2010-01-29  1152  	struct sk_buff *skb;
012873d057a449 Michael S. Tsirkin     2014-10-24  1153  	struct virtio_net_hdr_mrg_rxbuf *hdr;
8bcc65dfaae785 Andrew Melnychenko     2021-10-31  1154  	struct virtio_net_hdr_v1_hash *hdr_hash;
8bcc65dfaae785 Andrew Melnychenko     2021-10-31  1155  	enum pkt_hash_types rss_hash_type;
fb6813f480806d Rusty Russell          2008-07-25  1156  
bcff3162f3e027 Michael S. Tsirkin     2014-10-24  1157  	if (unlikely(len < vi->hdr_len + ETH_HLEN)) {
9ab86bbcf8be75 Shirley Ma             2010-01-29  1158  		pr_debug("%s: short packet %i\n", dev->name, len);
9ab86bbcf8be75 Shirley Ma             2010-01-29  1159  		dev->stats.rx_length_errors++;
ab7db91705e95e Michael Dalton         2014-01-16  1160  		if (vi->mergeable_rx_bufs) {
680557cf79f826 Michael S. Tsirkin     2017-03-06  1161  			put_page(virt_to_head_page(buf));
ab7db91705e95e Michael Dalton         2014-01-16  1162  		} else if (vi->big_packets) {
98bfd23cdb30e6 Michael Dalton         2013-12-05  1163  			give_pages(rq, buf);
ab7db91705e95e Michael Dalton         2014-01-16  1164  		} else {
f6b10209b90d48 Jason Wang             2017-02-21  1165  			put_page(virt_to_head_page(buf));
ab7db91705e95e Michael Dalton         2014-01-16  1166  		}
7d9d60fd4ab696 Toshiaki Makita        2018-07-23  1167  		return;
9ab86bbcf8be75 Shirley Ma             2010-01-29  1168  	}
9ab86bbcf8be75 Shirley Ma             2010-01-29  1169  
f121159d72091f Michael S. Tsirkin     2013-11-28  1170  	if (vi->mergeable_rx_bufs)
7d9d60fd4ab696 Toshiaki Makita        2018-07-23  1171  		skb = receive_mergeable(dev, vi, rq, buf, ctx, len, xdp_xmit,
a0929a44c2065d Toshiaki Makita        2018-07-23  1172  					stats);
f121159d72091f Michael S. Tsirkin     2013-11-28  1173  	else if (vi->big_packets)
a0929a44c2065d Toshiaki Makita        2018-07-23  1174  		skb = receive_big(dev, vi, rq, buf, len, stats);
f121159d72091f Michael S. Tsirkin     2013-11-28  1175  	else
a0929a44c2065d Toshiaki Makita        2018-07-23  1176  		skb = receive_small(dev, vi, rq, buf, ctx, len, xdp_xmit, stats);
f121159d72091f Michael S. Tsirkin     2013-11-28  1177  
8fc3b9e9a22977 Michael S. Tsirkin     2013-11-28  1178  	if (unlikely(!skb))
7d9d60fd4ab696 Toshiaki Makita        2018-07-23  1179  		return;
3f2c31d90327f2 Mark McLoughlin        2008-11-16  1180  
9ab86bbcf8be75 Shirley Ma             2010-01-29  1181  	hdr = skb_vnet_hdr(skb);
8bcc65dfaae785 Andrew Melnychenko     2021-10-31  1182  	if (vi->has_rss_hash_report && (dev->features & NETIF_F_RXHASH)) {
8bcc65dfaae785 Andrew Melnychenko     2021-10-31  1183  		hdr_hash = (struct virtio_net_hdr_v1_hash *)(hdr);
8bcc65dfaae785 Andrew Melnychenko     2021-10-31  1184  
8bcc65dfaae785 Andrew Melnychenko     2021-10-31 @1185  		switch (hdr_hash->hash_report) {
8bcc65dfaae785 Andrew Melnychenko     2021-10-31  1186  		case VIRTIO_NET_HASH_REPORT_TCPv4:
8bcc65dfaae785 Andrew Melnychenko     2021-10-31  1187  		case VIRTIO_NET_HASH_REPORT_UDPv4:
8bcc65dfaae785 Andrew Melnychenko     2021-10-31  1188  		case VIRTIO_NET_HASH_REPORT_TCPv6:
8bcc65dfaae785 Andrew Melnychenko     2021-10-31  1189  		case VIRTIO_NET_HASH_REPORT_UDPv6:
8bcc65dfaae785 Andrew Melnychenko     2021-10-31  1190  		case VIRTIO_NET_HASH_REPORT_TCPv6_EX:
8bcc65dfaae785 Andrew Melnychenko     2021-10-31  1191  		case VIRTIO_NET_HASH_REPORT_UDPv6_EX:
8bcc65dfaae785 Andrew Melnychenko     2021-10-31  1192  			rss_hash_type = PKT_HASH_TYPE_L4;
8bcc65dfaae785 Andrew Melnychenko     2021-10-31  1193  			break;
8bcc65dfaae785 Andrew Melnychenko     2021-10-31  1194  		case VIRTIO_NET_HASH_REPORT_IPv4:
8bcc65dfaae785 Andrew Melnychenko     2021-10-31  1195  		case VIRTIO_NET_HASH_REPORT_IPv6:
8bcc65dfaae785 Andrew Melnychenko     2021-10-31  1196  		case VIRTIO_NET_HASH_REPORT_IPv6_EX:
8bcc65dfaae785 Andrew Melnychenko     2021-10-31  1197  			rss_hash_type = PKT_HASH_TYPE_L3;
8bcc65dfaae785 Andrew Melnychenko     2021-10-31  1198  			break;
8bcc65dfaae785 Andrew Melnychenko     2021-10-31  1199  		case VIRTIO_NET_HASH_REPORT_NONE:
8bcc65dfaae785 Andrew Melnychenko     2021-10-31  1200  		default:
8bcc65dfaae785 Andrew Melnychenko     2021-10-31  1201  			rss_hash_type = PKT_HASH_TYPE_NONE;
8bcc65dfaae785 Andrew Melnychenko     2021-10-31  1202  		}
8bcc65dfaae785 Andrew Melnychenko     2021-10-31 @1203  		skb_set_hash(skb, hdr_hash->hash_value, rss_hash_type);
8bcc65dfaae785 Andrew Melnychenko     2021-10-31  1204  	}
3fa2a1df909482 stephen hemminger      2011-06-15  1205  
e858fae2b0b8f4 Mike Rapoport          2016-06-08  1206  	if (hdr->hdr.flags & VIRTIO_NET_HDR_F_DATA_VALID)
10a8d94a95742b Jason Wang             2011-06-10  1207  		skb->ip_summed = CHECKSUM_UNNECESSARY;
296f96fcfc160e Rusty Russell          2007-10-22  1208  
e858fae2b0b8f4 Mike Rapoport          2016-06-08  1209  	if (virtio_net_hdr_to_skb(skb, &hdr->hdr,
e858fae2b0b8f4 Mike Rapoport          2016-06-08  1210  				  virtio_is_little_endian(vi->vdev))) {
e858fae2b0b8f4 Mike Rapoport          2016-06-08  1211  		net_warn_ratelimited("%s: bad gso: type: %u, size: %u\n",
e858fae2b0b8f4 Mike Rapoport          2016-06-08  1212  				     dev->name, hdr->hdr.gso_type,
fdd819b21576c3 Michael S. Tsirkin     2014-10-07  1213  				     hdr->hdr.gso_size);
296f96fcfc160e Rusty Russell          2007-10-22  1214  		goto frame_err;
296f96fcfc160e Rusty Russell          2007-10-22  1215  	}
296f96fcfc160e Rusty Russell          2007-10-22  1216  
133bbb18ab1a2f Willem de Bruijn       2019-01-17  1217  	skb_record_rx_queue(skb, vq2rxq(rq->vq));
d1dc06dcd0f8fc Mike Rapoport          2016-06-14  1218  	skb->protocol = eth_type_trans(skb, dev);
d1dc06dcd0f8fc Mike Rapoport          2016-06-14  1219  	pr_debug("Receiving skb proto 0x%04x len %i type %i\n",
d1dc06dcd0f8fc Mike Rapoport          2016-06-14  1220  		 ntohs(skb->protocol), skb->len, skb->pkt_type);
d1dc06dcd0f8fc Mike Rapoport          2016-06-14  1221  
0fbd050a7d262b Eric Dumazet           2015-07-31  1222  	napi_gro_receive(&rq->napi, skb);
7d9d60fd4ab696 Toshiaki Makita        2018-07-23  1223  	return;
296f96fcfc160e Rusty Russell          2007-10-22  1224  
296f96fcfc160e Rusty Russell          2007-10-22  1225  frame_err:
296f96fcfc160e Rusty Russell          2007-10-22  1226  	dev->stats.rx_frame_errors++;
296f96fcfc160e Rusty Russell          2007-10-22  1227  	dev_kfree_skb(skb);
296f96fcfc160e Rusty Russell          2007-10-22  1228  }
296f96fcfc160e Rusty Russell          2007-10-22  1229  

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 33622 bytes --]

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [RFC PATCH 2/4] drivers/net/virtio_net: Changed mergeable buffer length calculation.
  2021-11-01  8:44     ` Michael S. Tsirkin
@ 2021-11-17  6:00       ` Andrew Melnichenko
  -1 siblings, 0 replies; 27+ messages in thread
From: Andrew Melnichenko @ 2021-11-17  6:00 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Jason Wang, davem, kuba, virtualization, netdev, linux-kernel,
	Yuri Benditovich, Yan Vugenfirer

On Mon, Nov 1, 2021 at 10:44 AM Michael S. Tsirkin <mst@redhat.com> wrote:
>
> On Sun, Oct 31, 2021 at 06:59:57AM +0200, Andrew Melnychenko wrote:
> > Now minimal virtual header length is may include the entire v1 header
> > if the hash report were populated.
> >
> > Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
>
> subject isn't really descriptive. changed it how?
>
> And I couldn't really decypher what this log entry means either.
>

I'll change it in the next patch.
So, I've tried to ensure that the v1 header with the hash report will
be available if required in new patches.

> > ---
> >  drivers/net/virtio_net.c | 8 +++++---
> >  1 file changed, 5 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> > index b72b21ac8ebd..abca2e93355d 100644
> > --- a/drivers/net/virtio_net.c
> > +++ b/drivers/net/virtio_net.c
> > @@ -393,7 +393,9 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
> >       hdr_p = p;
> >
> >       hdr_len = vi->hdr_len;
> > -     if (vi->mergeable_rx_bufs)
> > +     if (vi->has_rss_hash_report)
> > +             hdr_padded_len = sizeof(struct virtio_net_hdr_v1_hash);
> > +     else if (vi->mergeable_rx_bufs)
> >               hdr_padded_len = sizeof(*hdr);
> >       else
> >               hdr_padded_len = sizeof(struct padded_vnet_hdr);
> > @@ -1252,7 +1254,7 @@ static unsigned int get_mergeable_buf_len(struct receive_queue *rq,
> >                                         struct ewma_pkt_len *avg_pkt_len,
> >                                         unsigned int room)
> >  {
> > -     const size_t hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
> > +     const size_t hdr_len = ((struct virtnet_info *)(rq->vq->vdev->priv))->hdr_len;
> >       unsigned int len;
> >
> >       if (room)
>
> Is this pointer chasing the best we can do?

I'll change that.

>
> > @@ -2817,7 +2819,7 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
> >   */
> >  static unsigned int mergeable_min_buf_len(struct virtnet_info *vi, struct virtqueue *vq)
> >  {
> > -     const unsigned int hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
> > +     const unsigned int hdr_len = vi->hdr_len;
> >       unsigned int rq_size = virtqueue_get_vring_size(vq);
> >       unsigned int packet_len = vi->big_packets ? IP_MAX_MTU : vi->dev->max_mtu;
> >       unsigned int buf_len = hdr_len + ETH_HLEN + VLAN_HLEN + packet_len;
> > --
> > 2.33.1
>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [RFC PATCH 2/4] drivers/net/virtio_net: Changed mergeable buffer length calculation.
@ 2021-11-17  6:00       ` Andrew Melnichenko
  0 siblings, 0 replies; 27+ messages in thread
From: Andrew Melnichenko @ 2021-11-17  6:00 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: netdev, linux-kernel, virtualization, Yuri Benditovich,
	Yan Vugenfirer, kuba, davem

On Mon, Nov 1, 2021 at 10:44 AM Michael S. Tsirkin <mst@redhat.com> wrote:
>
> On Sun, Oct 31, 2021 at 06:59:57AM +0200, Andrew Melnychenko wrote:
> > Now minimal virtual header length is may include the entire v1 header
> > if the hash report were populated.
> >
> > Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
>
> subject isn't really descriptive. changed it how?
>
> And I couldn't really decypher what this log entry means either.
>

I'll change it in the next patch.
So, I've tried to ensure that the v1 header with the hash report will
be available if required in new patches.

> > ---
> >  drivers/net/virtio_net.c | 8 +++++---
> >  1 file changed, 5 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> > index b72b21ac8ebd..abca2e93355d 100644
> > --- a/drivers/net/virtio_net.c
> > +++ b/drivers/net/virtio_net.c
> > @@ -393,7 +393,9 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
> >       hdr_p = p;
> >
> >       hdr_len = vi->hdr_len;
> > -     if (vi->mergeable_rx_bufs)
> > +     if (vi->has_rss_hash_report)
> > +             hdr_padded_len = sizeof(struct virtio_net_hdr_v1_hash);
> > +     else if (vi->mergeable_rx_bufs)
> >               hdr_padded_len = sizeof(*hdr);
> >       else
> >               hdr_padded_len = sizeof(struct padded_vnet_hdr);
> > @@ -1252,7 +1254,7 @@ static unsigned int get_mergeable_buf_len(struct receive_queue *rq,
> >                                         struct ewma_pkt_len *avg_pkt_len,
> >                                         unsigned int room)
> >  {
> > -     const size_t hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
> > +     const size_t hdr_len = ((struct virtnet_info *)(rq->vq->vdev->priv))->hdr_len;
> >       unsigned int len;
> >
> >       if (room)
>
> Is this pointer chasing the best we can do?

I'll change that.

>
> > @@ -2817,7 +2819,7 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
> >   */
> >  static unsigned int mergeable_min_buf_len(struct virtnet_info *vi, struct virtqueue *vq)
> >  {
> > -     const unsigned int hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
> > +     const unsigned int hdr_len = vi->hdr_len;
> >       unsigned int rq_size = virtqueue_get_vring_size(vq);
> >       unsigned int packet_len = vi->big_packets ? IP_MAX_MTU : vi->dev->max_mtu;
> >       unsigned int buf_len = hdr_len + ETH_HLEN + VLAN_HLEN + packet_len;
> > --
> > 2.33.1
>
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [RFC PATCH 1/4] drivers/net/virtio_net: Fixed vheader to use v1.
  2021-11-01  8:40     ` Michael S. Tsirkin
@ 2021-11-17  6:00       ` Andrew Melnichenko
  -1 siblings, 0 replies; 27+ messages in thread
From: Andrew Melnichenko @ 2021-11-17  6:00 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Jason Wang, davem, kuba, virtualization, netdev, linux-kernel,
	Yuri Benditovich, Yan Vugenfirer

On Mon, Nov 1, 2021 at 10:40 AM Michael S. Tsirkin <mst@redhat.com> wrote:
>
> On Sun, Oct 31, 2021 at 06:59:56AM +0200, Andrew Melnychenko wrote:
> > The header v1 provides additional info about RSS.
> > Added changes to computing proper header length.
> > In the next patches, the header may contain RSS hash info
> > for the hash population.
> >
> > Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
> > ---
> >  drivers/net/virtio_net.c | 6 +++---
> >  1 file changed, 3 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> > index 4ad25a8b0870..b72b21ac8ebd 100644
> > --- a/drivers/net/virtio_net.c
> > +++ b/drivers/net/virtio_net.c
> > @@ -240,13 +240,13 @@ struct virtnet_info {
> >  };
> >
> >  struct padded_vnet_hdr {
> > -     struct virtio_net_hdr_mrg_rxbuf hdr;
> > +     struct virtio_net_hdr_v1_hash hdr;
> >       /*
> >        * hdr is in a separate sg buffer, and data sg buffer shares same page
> >        * with this header sg. This padding makes next sg 16 byte aligned
> >        * after the header.
> >        */
> > -     char padding[4];
> > +     char padding[12];
> >  };
> >
> >  static bool is_xdp_frame(void *ptr)
>
>
> This is not helpful as a separate patch, just reserving extra space.
> better squash with the patches making use of the change.

Ok.


>
> > @@ -1636,7 +1636,7 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
> >       const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
> >       struct virtnet_info *vi = sq->vq->vdev->priv;
> >       int num_sg;
> > -     unsigned hdr_len = vi->hdr_len;
> > +     unsigned int hdr_len = vi->hdr_len;
> >       bool can_push;
>
>
> if we want this, pls make it a separate patch.

Ok. I've added that change after checkpatch warnings. Technically,
checkpatch should not fail on the patch without that line.

>
>
> >
> >       pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest);
> > --
> > 2.33.1
>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [RFC PATCH 3/4] drivers/net/virtio_net: Added basic RSS support.
  2021-10-31 15:32     ` Willem de Bruijn
@ 2021-11-17  6:00       ` Andrew Melnichenko
  -1 siblings, 0 replies; 27+ messages in thread
From: Andrew Melnichenko @ 2021-11-17  6:00 UTC (permalink / raw)
  To: Willem de Bruijn
  Cc: Michael S. Tsirkin, Jason Wang, davem, kuba, virtualization,
	netdev, linux-kernel, Yuri Benditovich, Yan Vugenfirer

On Sun, Oct 31, 2021 at 5:33 PM Willem de Bruijn
<willemdebruijn.kernel@gmail.com> wrote:
>
> On Sun, Oct 31, 2021 at 1:00 AM Andrew Melnychenko <andrew@daynix.com> wrote:
> >
> > Added features for RSS and RSS hash report.
> > Added initialization, RXHASH feature and ethtool ops.
> > By default RSS/RXHASH is disabled.
> > Added ethtools ops to set key and indirection table.
> >
> > Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
> > ---
> >  drivers/net/virtio_net.c | 232 +++++++++++++++++++++++++++++++++++++--
> >  1 file changed, 223 insertions(+), 9 deletions(-)
> >
> > diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> > index abca2e93355d..cff7340f40bb 100644
> > --- a/drivers/net/virtio_net.c
> > +++ b/drivers/net/virtio_net.c
> > @@ -167,6 +167,28 @@ struct receive_queue {
> >         struct xdp_rxq_info xdp_rxq;
> >  };
> >
> > +/* This structure can contain rss message with maximum settings for indirection table and keysize
> > + * Note, that default structure that describes RSS configuration virtio_net_rss_config
> > + * contains same info but can't handle table values.
> > + * In any case, structure would be passed to virtio hw through sg_buf split by parts
> > + * because table sizes may be differ according to the device configuration.
> > + */
> > +#define VIRTIO_NET_RSS_MAX_KEY_SIZE     40
>
> Unless there is a technical reason, this probably should be no shorter
> than TOEPLITZ_KEY_LEN

Well yeah, technically if the device requests for shorter key, we
still may provide it.
I think we may check and 'disable' RSS if some configurations are inadequate.

>
> > +#define VIRTIO_NET_RSS_MAX_TABLE_LEN    128
> > +struct virtio_net_ctrl_rss {
> > +       struct {
> > +               __le32 hash_types;
> > +               __le16 indirection_table_mask;
> > +               __le16 unclassified_queue;
>
> Is this explicit variable needed?

Yes, it's a part of the message to be sent to the device.

>
> > +       } __packed table_info;
> > +       u16 indirection_table[VIRTIO_NET_RSS_MAX_TABLE_LEN];
> > +       struct {
> > +               u16 max_tx_vq; /* queues */
> > +               u8 hash_key_length;
> > +       } __packed key_info;
> > +       u8 key[VIRTIO_NET_RSS_MAX_KEY_SIZE];
> > +};
> > +
> >  /* Control VQ buffers: protected by the rtnl lock */
> >  struct control_buf {
> >         struct virtio_net_ctrl_hdr hdr;
> > @@ -176,6 +198,7 @@ struct control_buf {
> >         u8 allmulti;
> >         __virtio16 vid;
> >         __virtio64 offloads;
> > +       struct virtio_net_ctrl_rss rss;
> >  };
> >
> >  struct virtnet_info {
> > @@ -204,6 +227,12 @@ struct virtnet_info {
> >         /* Host will merge rx buffers for big packets (shake it! shake it!) */
> >         bool mergeable_rx_bufs;
> >
> > +       /* Host supports rss and/or hash report */
> > +       bool has_rss;
>
> Superfluous, can be derived form non-zero rss_key_size?

I think that the explicit 'has_rss' field is better. "non-zero
rss_key_size" should work, I'll change RSS derivation in the next
patches.

>
> > +       bool has_rss_hash_report;
> > +       u8 rss_key_size;
> > +       u16 rss_indir_table_size;
> > +
> >         /* Has control virtqueue */
> >         bool has_cvq;
> >
> > @@ -1119,6 +1148,8 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
> >         struct net_device *dev = vi->dev;
> >         struct sk_buff *skb;
> >         struct virtio_net_hdr_mrg_rxbuf *hdr;
> > +       struct virtio_net_hdr_v1_hash *hdr_hash;
> > +       enum pkt_hash_types rss_hash_type;
> >
> >         if (unlikely(len < vi->hdr_len + ETH_HLEN)) {
> >                 pr_debug("%s: short packet %i\n", dev->name, len);
> > @@ -1145,6 +1176,29 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
> >                 return;
> >
> >         hdr = skb_vnet_hdr(skb);
> > +       if (vi->has_rss_hash_report && (dev->features & NETIF_F_RXHASH)) {
>
> Only the second test is needed? It should be impossible to configure
> the feature unless the device advertises has_rss_hash_report

Well, you can have RSS without a hash population. So, need to check,
is the device supports hash population and rxhash is enabled(g.e.
through ethtool).

>
> > +               hdr_hash = (struct virtio_net_hdr_v1_hash *)(hdr);
> > +
> > +               switch (hdr_hash->hash_report) {
> > +               case VIRTIO_NET_HASH_REPORT_TCPv4:
> > +               case VIRTIO_NET_HASH_REPORT_UDPv4:
> > +               case VIRTIO_NET_HASH_REPORT_TCPv6:
> > +               case VIRTIO_NET_HASH_REPORT_UDPv6:
> > +               case VIRTIO_NET_HASH_REPORT_TCPv6_EX:
> > +               case VIRTIO_NET_HASH_REPORT_UDPv6_EX:
> > +                       rss_hash_type = PKT_HASH_TYPE_L4;
> > +                       break;
> > +               case VIRTIO_NET_HASH_REPORT_IPv4:
> > +               case VIRTIO_NET_HASH_REPORT_IPv6:
> > +               case VIRTIO_NET_HASH_REPORT_IPv6_EX:
> > +                       rss_hash_type = PKT_HASH_TYPE_L3;
> > +                       break;
> > +               case VIRTIO_NET_HASH_REPORT_NONE:
> > +               default:
> > +                       rss_hash_type = PKT_HASH_TYPE_NONE;
> > +               }
>
> Is this detailed protocol typing necessary? Most devices only pass a bit is_l4.

Yes, in theory, there is real hardware that may support only L3 hash
calculations.

>
> > +               skb_set_hash(skb, hdr_hash->hash_value, rss_hash_type);
> > +       }
> >
> >         if (hdr->hdr.flags & VIRTIO_NET_HDR_F_DATA_VALID)
> >                 skb->ip_summed = CHECKSUM_UNNECESSARY;
> > @@ -2167,6 +2221,57 @@ static void virtnet_get_ringparam(struct net_device *dev,
> >         ring->tx_pending = ring->tx_max_pending;
> >  }
> >
> > +static bool virtnet_commit_rss_command(struct virtnet_info *vi)
> > +{
> > +       struct net_device *dev = vi->dev;
> > +       struct scatterlist sgs[4];
> > +       unsigned int sg_buf_size;
> > +
> > +       /* prepare sgs */
> > +       sg_init_table(sgs, 4);
> > +
> > +       sg_buf_size = sizeof(vi->ctrl->rss.table_info);
> > +       sg_set_buf(&sgs[0], &vi->ctrl->rss.table_info, sg_buf_size);
> > +
> > +       sg_buf_size = sizeof(uint16_t) * vi->rss_indir_table_size;
> > +       sg_set_buf(&sgs[1], vi->ctrl->rss.indirection_table, sg_buf_size);
> > +
> > +       sg_buf_size = sizeof(vi->ctrl->rss.key_info);
> > +       sg_set_buf(&sgs[2], &vi->ctrl->rss.key_info, sg_buf_size);
> > +
> > +       sg_buf_size = vi->rss_key_size;
> > +       sg_set_buf(&sgs[3], vi->ctrl->rss.key, sg_buf_size);
> > +
> > +       if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MQ,
> > +                                 vi->has_rss ? VIRTIO_NET_CTRL_MQ_RSS_CONFIG
> > +                                 : VIRTIO_NET_CTRL_MQ_HASH_CONFIG, sgs)) {
> > +               dev_warn(&dev->dev, "VIRTIONET issue with committing RSS sgs\n");
> > +               return false;
> > +       }
> > +       return true;
> > +}
> > +
> > +static void virtnet_init_default_rss(struct virtnet_info *vi)
> > +{
> > +       u32 indir_val = 0;
> > +       int i = 0;
> > +
> > +       vi->ctrl->rss.table_info.hash_types = vi->rss_hash_types_supported;
>
> Similar to above, and related to the next patch: is this very detailed
> specification of supported hash types needed? When is this useful? It
> is not customary to specify RSS to that degree.

In theory, there are real devices that implement virtio_net with(or
without) some supported hashes.

>
> > +       vi->rss_hash_types_saved = vi->rss_hash_types_supported;
> > +       vi->ctrl->rss.table_info.indirection_table_mask = vi->rss_indir_table_size - 1;
> > +       vi->ctrl->rss.table_info.unclassified_queue = 0;
> > +
> > +       for (; i < vi->rss_indir_table_size; ++i) {
> > +               indir_val = ethtool_rxfh_indir_default(i, vi->max_queue_pairs);
> > +               vi->ctrl->rss.indirection_table[i] = indir_val;
> > +       }
> > +
> > +       vi->ctrl->rss.key_info.max_tx_vq = vi->curr_queue_pairs;
> > +       vi->ctrl->rss.key_info.hash_key_length = vi->rss_key_size;
> > +
> > +       netdev_rss_key_fill(vi->ctrl->rss.key, vi->rss_key_size);
> > +}
> > +
> >
> >  static void virtnet_get_drvinfo(struct net_device *dev,
> >                                 struct ethtool_drvinfo *info)
> > @@ -2395,6 +2500,71 @@ static void virtnet_update_settings(struct virtnet_info *vi)
> >                 vi->duplex = duplex;
> >  }
> >
> > +static u32 virtnet_get_rxfh_key_size(struct net_device *dev)
> > +{
> > +       return ((struct virtnet_info *)netdev_priv(dev))->rss_key_size;
> > +}
> > +
> > +static u32 virtnet_get_rxfh_indir_size(struct net_device *dev)
> > +{
> > +       return ((struct virtnet_info *)netdev_priv(dev))->rss_indir_table_size;
> > +}
> > +
> > +static int virtnet_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc)
> > +{
> > +       struct virtnet_info *vi = netdev_priv(dev);
> > +       int i;
> > +
> > +       if (indir) {
> > +               for (i = 0; i < vi->rss_indir_table_size; ++i)
> > +                       indir[i] = vi->ctrl->rss.indirection_table[i];
> > +       }
> > +
> > +       if (key)
> > +               memcpy(key, vi->ctrl->rss.key, vi->rss_key_size);
> > +
> > +       if (hfunc)
> > +               *hfunc = ETH_RSS_HASH_TOP;
> > +
> > +       return 0;
> > +}
> > +
> > +static int virtnet_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key, const u8 hfunc)
> > +{
> > +       struct virtnet_info *vi = netdev_priv(dev);
> > +       int i;
> > +
> > +       if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
> > +               return -EOPNOTSUPP;
> > +
> > +       if (indir) {
> > +               for (i = 0; i < vi->rss_indir_table_size; ++i)
> > +                       vi->ctrl->rss.indirection_table[i] = indir[i];
> > +       }
> > +       if (key)
> > +               memcpy(vi->ctrl->rss.key, key, vi->rss_key_size);
> > +
> > +       virtnet_commit_rss_command(vi);
> > +
> > +       return 0;
> > +}
> > +
> > +static int virtnet_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, u32 *rule_locs)
> > +{
> > +       struct virtnet_info *vi = netdev_priv(dev);
> > +       int rc = 0;
> > +
> > +       switch (info->cmd) {
> > +       case ETHTOOL_GRXRINGS:
> > +               info->data = vi->curr_queue_pairs;
> > +               break;
> > +       default:
> > +               rc = -EOPNOTSUPP;
> > +       }
> > +
> > +       return rc;
> > +}
> > +
> >  static const struct ethtool_ops virtnet_ethtool_ops = {
> >         .supported_coalesce_params = ETHTOOL_COALESCE_MAX_FRAMES,
> >         .get_drvinfo = virtnet_get_drvinfo,
> > @@ -2410,6 +2580,11 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
> >         .set_link_ksettings = virtnet_set_link_ksettings,
> >         .set_coalesce = virtnet_set_coalesce,
> >         .get_coalesce = virtnet_get_coalesce,
> > +       .get_rxfh_key_size = virtnet_get_rxfh_key_size,
> > +       .get_rxfh_indir_size = virtnet_get_rxfh_indir_size,
> > +       .get_rxfh = virtnet_get_rxfh,
> > +       .set_rxfh = virtnet_set_rxfh,
> > +       .get_rxnfc = virtnet_get_rxnfc,
> >  };
> >
> >  static void virtnet_freeze_down(struct virtio_device *vdev)
> > @@ -3040,7 +3215,10 @@ static bool virtnet_validate_features(struct virtio_device *vdev)
> >                              "VIRTIO_NET_F_CTRL_VQ") ||
> >              VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_MQ, "VIRTIO_NET_F_CTRL_VQ") ||
> >              VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR,
> > -                            "VIRTIO_NET_F_CTRL_VQ"))) {
> > +                            "VIRTIO_NET_F_CTRL_VQ") ||
> > +            VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_RSS, "VIRTIO_NET_F_RSS") ||
> > +            VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_HASH_REPORT,
> > +                            "VIRTIO_NET_F_HASH_REPORT"))) {
> >                 return false;
> >         }
> >
> > @@ -3080,13 +3258,14 @@ static int virtnet_probe(struct virtio_device *vdev)
> >         u16 max_queue_pairs;
> >         int mtu;
> >
> > -       /* Find if host supports multiqueue virtio_net device */
> > -       err = virtio_cread_feature(vdev, VIRTIO_NET_F_MQ,
> > -                                  struct virtio_net_config,
> > -                                  max_virtqueue_pairs, &max_queue_pairs);
> > +       /* Find if host supports multiqueue/rss virtio_net device */
> > +       max_queue_pairs = 0;
> > +       if (virtio_has_feature(vdev, VIRTIO_NET_F_MQ) || virtio_has_feature(vdev, VIRTIO_NET_F_RSS))
>
> Is VIRTIO_NET_F_RSS implied by VIRTIO_NET_F_MQ?

MQ and/or RSS sets multiqueue, like so:
>    virtio_net_set_multiqueue(n,
>                              virtio_has_feature(features, VIRTIO_NET_F_RSS) ||
>                              virtio_has_feature(features, VIRTIO_NET_F_MQ));

So, technically it's possible to create a virtual net only with RSS without mq.

>
> > +               max_queue_pairs =
> > +                    virtio_cread16(vdev, offsetof(struct virtio_net_config, max_virtqueue_pairs));
> >
> >         /* We need at least 2 queue's */
> > -       if (err || max_queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
> > +       if (max_queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
> >             max_queue_pairs > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX ||
> >             !virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
> >                 max_queue_pairs = 1;
> > @@ -3170,8 +3349,36 @@ static int virtnet_probe(struct virtio_device *vdev)
> >         if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
> >                 vi->mergeable_rx_bufs = true;
> >
> > -       if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF) ||
> > -           virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
> > +       if (virtio_has_feature(vdev, VIRTIO_NET_F_HASH_REPORT)) {
> > +               vi->has_rss_hash_report = true;
> > +               vi->rss_indir_table_size = 1;
> > +               vi->rss_key_size = VIRTIO_NET_RSS_MAX_KEY_SIZE;
> > +       }
> > +
> > +       if (virtio_has_feature(vdev, VIRTIO_NET_F_RSS)) {
> > +               vi->has_rss = true;
> > +               vi->rss_indir_table_size =
> > +                       virtio_cread16(vdev, offsetof(struct virtio_net_config,
> > +                                                     rss_max_indirection_table_length));
> > +               vi->rss_key_size =
> > +                       virtio_cread8(vdev, offsetof(struct virtio_net_config, rss_max_key_size));
> > +       }
>
> Please split adding the two features, hash report and rss, into two
> separate patches.

It may provide dead code that will be replaced by code in 'hash
report' report patch.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [RFC PATCH 1/4] drivers/net/virtio_net: Fixed vheader to use v1.
@ 2021-11-17  6:00       ` Andrew Melnichenko
  0 siblings, 0 replies; 27+ messages in thread
From: Andrew Melnichenko @ 2021-11-17  6:00 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: netdev, linux-kernel, virtualization, Yuri Benditovich,
	Yan Vugenfirer, kuba, davem

On Mon, Nov 1, 2021 at 10:40 AM Michael S. Tsirkin <mst@redhat.com> wrote:
>
> On Sun, Oct 31, 2021 at 06:59:56AM +0200, Andrew Melnychenko wrote:
> > The header v1 provides additional info about RSS.
> > Added changes to computing proper header length.
> > In the next patches, the header may contain RSS hash info
> > for the hash population.
> >
> > Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
> > ---
> >  drivers/net/virtio_net.c | 6 +++---
> >  1 file changed, 3 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> > index 4ad25a8b0870..b72b21ac8ebd 100644
> > --- a/drivers/net/virtio_net.c
> > +++ b/drivers/net/virtio_net.c
> > @@ -240,13 +240,13 @@ struct virtnet_info {
> >  };
> >
> >  struct padded_vnet_hdr {
> > -     struct virtio_net_hdr_mrg_rxbuf hdr;
> > +     struct virtio_net_hdr_v1_hash hdr;
> >       /*
> >        * hdr is in a separate sg buffer, and data sg buffer shares same page
> >        * with this header sg. This padding makes next sg 16 byte aligned
> >        * after the header.
> >        */
> > -     char padding[4];
> > +     char padding[12];
> >  };
> >
> >  static bool is_xdp_frame(void *ptr)
>
>
> This is not helpful as a separate patch, just reserving extra space.
> better squash with the patches making use of the change.

Ok.


>
> > @@ -1636,7 +1636,7 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
> >       const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
> >       struct virtnet_info *vi = sq->vq->vdev->priv;
> >       int num_sg;
> > -     unsigned hdr_len = vi->hdr_len;
> > +     unsigned int hdr_len = vi->hdr_len;
> >       bool can_push;
>
>
> if we want this, pls make it a separate patch.

Ok. I've added that change after checkpatch warnings. Technically,
checkpatch should not fail on the patch without that line.

>
>
> >
> >       pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest);
> > --
> > 2.33.1
>
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [RFC PATCH 3/4] drivers/net/virtio_net: Added basic RSS support.
@ 2021-11-17  6:00       ` Andrew Melnichenko
  0 siblings, 0 replies; 27+ messages in thread
From: Andrew Melnichenko @ 2021-11-17  6:00 UTC (permalink / raw)
  To: Willem de Bruijn
  Cc: Michael S. Tsirkin, netdev, linux-kernel, virtualization,
	Yuri Benditovich, Yan Vugenfirer, kuba, davem

On Sun, Oct 31, 2021 at 5:33 PM Willem de Bruijn
<willemdebruijn.kernel@gmail.com> wrote:
>
> On Sun, Oct 31, 2021 at 1:00 AM Andrew Melnychenko <andrew@daynix.com> wrote:
> >
> > Added features for RSS and RSS hash report.
> > Added initialization, RXHASH feature and ethtool ops.
> > By default RSS/RXHASH is disabled.
> > Added ethtools ops to set key and indirection table.
> >
> > Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
> > ---
> >  drivers/net/virtio_net.c | 232 +++++++++++++++++++++++++++++++++++++--
> >  1 file changed, 223 insertions(+), 9 deletions(-)
> >
> > diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> > index abca2e93355d..cff7340f40bb 100644
> > --- a/drivers/net/virtio_net.c
> > +++ b/drivers/net/virtio_net.c
> > @@ -167,6 +167,28 @@ struct receive_queue {
> >         struct xdp_rxq_info xdp_rxq;
> >  };
> >
> > +/* This structure can contain rss message with maximum settings for indirection table and keysize
> > + * Note, that default structure that describes RSS configuration virtio_net_rss_config
> > + * contains same info but can't handle table values.
> > + * In any case, structure would be passed to virtio hw through sg_buf split by parts
> > + * because table sizes may be differ according to the device configuration.
> > + */
> > +#define VIRTIO_NET_RSS_MAX_KEY_SIZE     40
>
> Unless there is a technical reason, this probably should be no shorter
> than TOEPLITZ_KEY_LEN

Well yeah, technically if the device requests for shorter key, we
still may provide it.
I think we may check and 'disable' RSS if some configurations are inadequate.

>
> > +#define VIRTIO_NET_RSS_MAX_TABLE_LEN    128
> > +struct virtio_net_ctrl_rss {
> > +       struct {
> > +               __le32 hash_types;
> > +               __le16 indirection_table_mask;
> > +               __le16 unclassified_queue;
>
> Is this explicit variable needed?

Yes, it's a part of the message to be sent to the device.

>
> > +       } __packed table_info;
> > +       u16 indirection_table[VIRTIO_NET_RSS_MAX_TABLE_LEN];
> > +       struct {
> > +               u16 max_tx_vq; /* queues */
> > +               u8 hash_key_length;
> > +       } __packed key_info;
> > +       u8 key[VIRTIO_NET_RSS_MAX_KEY_SIZE];
> > +};
> > +
> >  /* Control VQ buffers: protected by the rtnl lock */
> >  struct control_buf {
> >         struct virtio_net_ctrl_hdr hdr;
> > @@ -176,6 +198,7 @@ struct control_buf {
> >         u8 allmulti;
> >         __virtio16 vid;
> >         __virtio64 offloads;
> > +       struct virtio_net_ctrl_rss rss;
> >  };
> >
> >  struct virtnet_info {
> > @@ -204,6 +227,12 @@ struct virtnet_info {
> >         /* Host will merge rx buffers for big packets (shake it! shake it!) */
> >         bool mergeable_rx_bufs;
> >
> > +       /* Host supports rss and/or hash report */
> > +       bool has_rss;
>
> Superfluous, can be derived form non-zero rss_key_size?

I think that the explicit 'has_rss' field is better. "non-zero
rss_key_size" should work, I'll change RSS derivation in the next
patches.

>
> > +       bool has_rss_hash_report;
> > +       u8 rss_key_size;
> > +       u16 rss_indir_table_size;
> > +
> >         /* Has control virtqueue */
> >         bool has_cvq;
> >
> > @@ -1119,6 +1148,8 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
> >         struct net_device *dev = vi->dev;
> >         struct sk_buff *skb;
> >         struct virtio_net_hdr_mrg_rxbuf *hdr;
> > +       struct virtio_net_hdr_v1_hash *hdr_hash;
> > +       enum pkt_hash_types rss_hash_type;
> >
> >         if (unlikely(len < vi->hdr_len + ETH_HLEN)) {
> >                 pr_debug("%s: short packet %i\n", dev->name, len);
> > @@ -1145,6 +1176,29 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
> >                 return;
> >
> >         hdr = skb_vnet_hdr(skb);
> > +       if (vi->has_rss_hash_report && (dev->features & NETIF_F_RXHASH)) {
>
> Only the second test is needed? It should be impossible to configure
> the feature unless the device advertises has_rss_hash_report

Well, you can have RSS without a hash population. So, need to check,
is the device supports hash population and rxhash is enabled(g.e.
through ethtool).

>
> > +               hdr_hash = (struct virtio_net_hdr_v1_hash *)(hdr);
> > +
> > +               switch (hdr_hash->hash_report) {
> > +               case VIRTIO_NET_HASH_REPORT_TCPv4:
> > +               case VIRTIO_NET_HASH_REPORT_UDPv4:
> > +               case VIRTIO_NET_HASH_REPORT_TCPv6:
> > +               case VIRTIO_NET_HASH_REPORT_UDPv6:
> > +               case VIRTIO_NET_HASH_REPORT_TCPv6_EX:
> > +               case VIRTIO_NET_HASH_REPORT_UDPv6_EX:
> > +                       rss_hash_type = PKT_HASH_TYPE_L4;
> > +                       break;
> > +               case VIRTIO_NET_HASH_REPORT_IPv4:
> > +               case VIRTIO_NET_HASH_REPORT_IPv6:
> > +               case VIRTIO_NET_HASH_REPORT_IPv6_EX:
> > +                       rss_hash_type = PKT_HASH_TYPE_L3;
> > +                       break;
> > +               case VIRTIO_NET_HASH_REPORT_NONE:
> > +               default:
> > +                       rss_hash_type = PKT_HASH_TYPE_NONE;
> > +               }
>
> Is this detailed protocol typing necessary? Most devices only pass a bit is_l4.

Yes, in theory, there is real hardware that may support only L3 hash
calculations.

>
> > +               skb_set_hash(skb, hdr_hash->hash_value, rss_hash_type);
> > +       }
> >
> >         if (hdr->hdr.flags & VIRTIO_NET_HDR_F_DATA_VALID)
> >                 skb->ip_summed = CHECKSUM_UNNECESSARY;
> > @@ -2167,6 +2221,57 @@ static void virtnet_get_ringparam(struct net_device *dev,
> >         ring->tx_pending = ring->tx_max_pending;
> >  }
> >
> > +static bool virtnet_commit_rss_command(struct virtnet_info *vi)
> > +{
> > +       struct net_device *dev = vi->dev;
> > +       struct scatterlist sgs[4];
> > +       unsigned int sg_buf_size;
> > +
> > +       /* prepare sgs */
> > +       sg_init_table(sgs, 4);
> > +
> > +       sg_buf_size = sizeof(vi->ctrl->rss.table_info);
> > +       sg_set_buf(&sgs[0], &vi->ctrl->rss.table_info, sg_buf_size);
> > +
> > +       sg_buf_size = sizeof(uint16_t) * vi->rss_indir_table_size;
> > +       sg_set_buf(&sgs[1], vi->ctrl->rss.indirection_table, sg_buf_size);
> > +
> > +       sg_buf_size = sizeof(vi->ctrl->rss.key_info);
> > +       sg_set_buf(&sgs[2], &vi->ctrl->rss.key_info, sg_buf_size);
> > +
> > +       sg_buf_size = vi->rss_key_size;
> > +       sg_set_buf(&sgs[3], vi->ctrl->rss.key, sg_buf_size);
> > +
> > +       if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MQ,
> > +                                 vi->has_rss ? VIRTIO_NET_CTRL_MQ_RSS_CONFIG
> > +                                 : VIRTIO_NET_CTRL_MQ_HASH_CONFIG, sgs)) {
> > +               dev_warn(&dev->dev, "VIRTIONET issue with committing RSS sgs\n");
> > +               return false;
> > +       }
> > +       return true;
> > +}
> > +
> > +static void virtnet_init_default_rss(struct virtnet_info *vi)
> > +{
> > +       u32 indir_val = 0;
> > +       int i = 0;
> > +
> > +       vi->ctrl->rss.table_info.hash_types = vi->rss_hash_types_supported;
>
> Similar to above, and related to the next patch: is this very detailed
> specification of supported hash types needed? When is this useful? It
> is not customary to specify RSS to that degree.

In theory, there are real devices that implement virtio_net with(or
without) some supported hashes.

>
> > +       vi->rss_hash_types_saved = vi->rss_hash_types_supported;
> > +       vi->ctrl->rss.table_info.indirection_table_mask = vi->rss_indir_table_size - 1;
> > +       vi->ctrl->rss.table_info.unclassified_queue = 0;
> > +
> > +       for (; i < vi->rss_indir_table_size; ++i) {
> > +               indir_val = ethtool_rxfh_indir_default(i, vi->max_queue_pairs);
> > +               vi->ctrl->rss.indirection_table[i] = indir_val;
> > +       }
> > +
> > +       vi->ctrl->rss.key_info.max_tx_vq = vi->curr_queue_pairs;
> > +       vi->ctrl->rss.key_info.hash_key_length = vi->rss_key_size;
> > +
> > +       netdev_rss_key_fill(vi->ctrl->rss.key, vi->rss_key_size);
> > +}
> > +
> >
> >  static void virtnet_get_drvinfo(struct net_device *dev,
> >                                 struct ethtool_drvinfo *info)
> > @@ -2395,6 +2500,71 @@ static void virtnet_update_settings(struct virtnet_info *vi)
> >                 vi->duplex = duplex;
> >  }
> >
> > +static u32 virtnet_get_rxfh_key_size(struct net_device *dev)
> > +{
> > +       return ((struct virtnet_info *)netdev_priv(dev))->rss_key_size;
> > +}
> > +
> > +static u32 virtnet_get_rxfh_indir_size(struct net_device *dev)
> > +{
> > +       return ((struct virtnet_info *)netdev_priv(dev))->rss_indir_table_size;
> > +}
> > +
> > +static int virtnet_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc)
> > +{
> > +       struct virtnet_info *vi = netdev_priv(dev);
> > +       int i;
> > +
> > +       if (indir) {
> > +               for (i = 0; i < vi->rss_indir_table_size; ++i)
> > +                       indir[i] = vi->ctrl->rss.indirection_table[i];
> > +       }
> > +
> > +       if (key)
> > +               memcpy(key, vi->ctrl->rss.key, vi->rss_key_size);
> > +
> > +       if (hfunc)
> > +               *hfunc = ETH_RSS_HASH_TOP;
> > +
> > +       return 0;
> > +}
> > +
> > +static int virtnet_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key, const u8 hfunc)
> > +{
> > +       struct virtnet_info *vi = netdev_priv(dev);
> > +       int i;
> > +
> > +       if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
> > +               return -EOPNOTSUPP;
> > +
> > +       if (indir) {
> > +               for (i = 0; i < vi->rss_indir_table_size; ++i)
> > +                       vi->ctrl->rss.indirection_table[i] = indir[i];
> > +       }
> > +       if (key)
> > +               memcpy(vi->ctrl->rss.key, key, vi->rss_key_size);
> > +
> > +       virtnet_commit_rss_command(vi);
> > +
> > +       return 0;
> > +}
> > +
> > +static int virtnet_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, u32 *rule_locs)
> > +{
> > +       struct virtnet_info *vi = netdev_priv(dev);
> > +       int rc = 0;
> > +
> > +       switch (info->cmd) {
> > +       case ETHTOOL_GRXRINGS:
> > +               info->data = vi->curr_queue_pairs;
> > +               break;
> > +       default:
> > +               rc = -EOPNOTSUPP;
> > +       }
> > +
> > +       return rc;
> > +}
> > +
> >  static const struct ethtool_ops virtnet_ethtool_ops = {
> >         .supported_coalesce_params = ETHTOOL_COALESCE_MAX_FRAMES,
> >         .get_drvinfo = virtnet_get_drvinfo,
> > @@ -2410,6 +2580,11 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
> >         .set_link_ksettings = virtnet_set_link_ksettings,
> >         .set_coalesce = virtnet_set_coalesce,
> >         .get_coalesce = virtnet_get_coalesce,
> > +       .get_rxfh_key_size = virtnet_get_rxfh_key_size,
> > +       .get_rxfh_indir_size = virtnet_get_rxfh_indir_size,
> > +       .get_rxfh = virtnet_get_rxfh,
> > +       .set_rxfh = virtnet_set_rxfh,
> > +       .get_rxnfc = virtnet_get_rxnfc,
> >  };
> >
> >  static void virtnet_freeze_down(struct virtio_device *vdev)
> > @@ -3040,7 +3215,10 @@ static bool virtnet_validate_features(struct virtio_device *vdev)
> >                              "VIRTIO_NET_F_CTRL_VQ") ||
> >              VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_MQ, "VIRTIO_NET_F_CTRL_VQ") ||
> >              VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR,
> > -                            "VIRTIO_NET_F_CTRL_VQ"))) {
> > +                            "VIRTIO_NET_F_CTRL_VQ") ||
> > +            VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_RSS, "VIRTIO_NET_F_RSS") ||
> > +            VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_HASH_REPORT,
> > +                            "VIRTIO_NET_F_HASH_REPORT"))) {
> >                 return false;
> >         }
> >
> > @@ -3080,13 +3258,14 @@ static int virtnet_probe(struct virtio_device *vdev)
> >         u16 max_queue_pairs;
> >         int mtu;
> >
> > -       /* Find if host supports multiqueue virtio_net device */
> > -       err = virtio_cread_feature(vdev, VIRTIO_NET_F_MQ,
> > -                                  struct virtio_net_config,
> > -                                  max_virtqueue_pairs, &max_queue_pairs);
> > +       /* Find if host supports multiqueue/rss virtio_net device */
> > +       max_queue_pairs = 0;
> > +       if (virtio_has_feature(vdev, VIRTIO_NET_F_MQ) || virtio_has_feature(vdev, VIRTIO_NET_F_RSS))
>
> Is VIRTIO_NET_F_RSS implied by VIRTIO_NET_F_MQ?

MQ and/or RSS sets multiqueue, like so:
>    virtio_net_set_multiqueue(n,
>                              virtio_has_feature(features, VIRTIO_NET_F_RSS) ||
>                              virtio_has_feature(features, VIRTIO_NET_F_MQ));

So, technically it's possible to create a virtual net only with RSS without mq.

>
> > +               max_queue_pairs =
> > +                    virtio_cread16(vdev, offsetof(struct virtio_net_config, max_virtqueue_pairs));
> >
> >         /* We need at least 2 queue's */
> > -       if (err || max_queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
> > +       if (max_queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
> >             max_queue_pairs > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX ||
> >             !virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
> >                 max_queue_pairs = 1;
> > @@ -3170,8 +3349,36 @@ static int virtnet_probe(struct virtio_device *vdev)
> >         if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
> >                 vi->mergeable_rx_bufs = true;
> >
> > -       if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF) ||
> > -           virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
> > +       if (virtio_has_feature(vdev, VIRTIO_NET_F_HASH_REPORT)) {
> > +               vi->has_rss_hash_report = true;
> > +               vi->rss_indir_table_size = 1;
> > +               vi->rss_key_size = VIRTIO_NET_RSS_MAX_KEY_SIZE;
> > +       }
> > +
> > +       if (virtio_has_feature(vdev, VIRTIO_NET_F_RSS)) {
> > +               vi->has_rss = true;
> > +               vi->rss_indir_table_size =
> > +                       virtio_cread16(vdev, offsetof(struct virtio_net_config,
> > +                                                     rss_max_indirection_table_length));
> > +               vi->rss_key_size =
> > +                       virtio_cread8(vdev, offsetof(struct virtio_net_config, rss_max_key_size));
> > +       }
>
> Please split adding the two features, hash report and rss, into two
> separate patches.

It may provide dead code that will be replaced by code in 'hash
report' report patch.
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2021-11-17  6:01 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-31  4:59 [RFC PATCH 0/4] Added RSS support Andrew Melnychenko
2021-10-31  4:59 ` Andrew Melnychenko
2021-10-31  4:59 ` [RFC PATCH 1/4] drivers/net/virtio_net: Fixed vheader to use v1 Andrew Melnychenko
2021-10-31  4:59   ` Andrew Melnychenko
2021-11-01  8:40   ` Michael S. Tsirkin
2021-11-01  8:40     ` Michael S. Tsirkin
2021-11-17  6:00     ` Andrew Melnichenko
2021-11-17  6:00       ` Andrew Melnichenko
2021-10-31  4:59 ` [RFC PATCH 2/4] drivers/net/virtio_net: Changed mergeable buffer length calculation Andrew Melnychenko
2021-10-31  4:59   ` Andrew Melnychenko
2021-10-31 16:11   ` kernel test robot
2021-11-01  8:44   ` Michael S. Tsirkin
2021-11-01  8:44     ` Michael S. Tsirkin
2021-11-17  6:00     ` Andrew Melnichenko
2021-11-17  6:00       ` Andrew Melnichenko
2021-10-31  4:59 ` [RFC PATCH 3/4] drivers/net/virtio_net: Added basic RSS support Andrew Melnychenko
2021-10-31  4:59   ` Andrew Melnychenko
2021-10-31 15:30   ` kernel test robot
2021-10-31 15:32   ` Willem de Bruijn
2021-10-31 15:32     ` Willem de Bruijn
2021-10-31 15:37     ` Willem de Bruijn
2021-10-31 15:37       ` Willem de Bruijn
2021-11-17  6:00     ` Andrew Melnichenko
2021-11-17  6:00       ` Andrew Melnichenko
2021-10-31  4:59 ` [RFC PATCH 4/4] drivers/net/virtio_net: Added RSS hash report control Andrew Melnychenko
2021-10-31  4:59   ` Andrew Melnychenko
2021-11-01 19:49   ` kernel test robot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.