All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 0/3] drivers/net/virtio_net: Added RSS support.
@ 2021-08-18 17:54 ` Andrew Melnychenko
  0 siblings, 0 replies; 19+ messages in thread
From: Andrew Melnychenko @ 2021-08-18 17:54 UTC (permalink / raw)
  To: mst, jasowang, davem, kuba; +Cc: virtualization, netdev, linux-kernel

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.

Andrew Melnychenko (3):
  drivers/net/virtio_net: Fixed vheader to use v1.
  drivers/net/virtio_net: Added basic RSS support.
  drivers/net/virtio_net: Added RSS hash report.

 drivers/net/virtio_net.c | 402 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 385 insertions(+), 17 deletions(-)

-- 
2.31.1


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

* [RFC PATCH 0/3] drivers/net/virtio_net: Added RSS support.
@ 2021-08-18 17:54 ` Andrew Melnychenko
  0 siblings, 0 replies; 19+ messages in thread
From: Andrew Melnychenko @ 2021-08-18 17:54 UTC (permalink / raw)
  To: mst, jasowang, davem, kuba; +Cc: netdev, 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.

Andrew Melnychenko (3):
  drivers/net/virtio_net: Fixed vheader to use v1.
  drivers/net/virtio_net: Added basic RSS support.
  drivers/net/virtio_net: Added RSS hash report.

 drivers/net/virtio_net.c | 402 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 385 insertions(+), 17 deletions(-)

-- 
2.31.1

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

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

* [RFC PATCH 1/3] drivers/net/virtio_net: Fixed vheader to use v1.
  2021-08-18 17:54 ` Andrew Melnychenko
@ 2021-08-18 17:54   ` Andrew Melnychenko
  -1 siblings, 0 replies; 19+ messages in thread
From: Andrew Melnychenko @ 2021-08-18 17:54 UTC (permalink / raw)
  To: mst, jasowang, davem, kuba; +Cc: virtualization, netdev, linux-kernel

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 | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 56c3f8519093..85427b4f51bc 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)
@@ -1258,7 +1258,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)
@@ -1642,7 +1642,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);
@@ -2819,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.31.1


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

* [RFC PATCH 1/3] drivers/net/virtio_net: Fixed vheader to use v1.
@ 2021-08-18 17:54   ` Andrew Melnychenko
  0 siblings, 0 replies; 19+ messages in thread
From: Andrew Melnychenko @ 2021-08-18 17:54 UTC (permalink / raw)
  To: mst, jasowang, davem, kuba; +Cc: netdev, 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 | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 56c3f8519093..85427b4f51bc 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)
@@ -1258,7 +1258,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)
@@ -1642,7 +1642,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);
@@ -2819,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.31.1

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

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

* [RFC PATCH 2/3] drivers/net/virtio_net: Added basic RSS support.
  2021-08-18 17:54 ` Andrew Melnychenko
@ 2021-08-18 17:54   ` Andrew Melnychenko
  -1 siblings, 0 replies; 19+ messages in thread
From: Andrew Melnychenko @ 2021-08-18 17:54 UTC (permalink / raw)
  To: mst, jasowang, davem, kuba; +Cc: virtualization, netdev, linux-kernel

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 | 215 ++++++++++++++++++++++++++++++++++++---
 1 file changed, 203 insertions(+), 12 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 85427b4f51bc..d87bde246305 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -167,6 +167,23 @@ struct receive_queue {
 	struct xdp_rxq_info xdp_rxq;
 };
 
+/* This structure can contain rss message with maximum settings for indirection table and keysize */
+#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 +193,7 @@ struct control_buf {
 	u8 allmulti;
 	__virtio16 vid;
 	__virtio64 offloads;
+	struct virtio_net_ctrl_rss rss;
 };
 
 struct virtnet_info {
@@ -204,6 +222,14 @@ 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;
+	u32 rss_hash_types_supported;
+	u32 rss_hash_types_saved;
+
 	/* Has control virtqueue */
 	bool has_cvq;
 
@@ -393,7 +419,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);
@@ -2171,6 +2199,56 @@ 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 +2473,72 @@ static void virtnet_update_settings(struct virtnet_info *vi)
 		vi->duplex = duplex;
 }
 
+u32 virtnet_get_rxfh_key_size(struct net_device *dev)
+{
+	return ((struct virtnet_info *)netdev_priv(dev))->rss_key_size;
+}
+
+u32 virtnet_get_rxfh_indir_size(struct net_device *dev)
+{
+	return ((struct virtnet_info *)netdev_priv(dev))->rss_indir_table_size;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+		rc = -EOPNOTSUPP;
+	}
+	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 +2554,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)
@@ -2662,6 +2811,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;
 }
 
@@ -3080,13 +3239,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;
@@ -3160,6 +3320,9 @@ static int virtnet_probe(struct virtio_device *vdev)
 
 	INIT_WORK(&vi->config_work, virtnet_config_changed_work);
 
+	if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
+		vi->has_cvq = true;
+
 	/* If we can receive ANY GSO packets, we must allocate large ones. */
 	if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) ||
 	    virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6) ||
@@ -3170,8 +3333,32 @@ 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 (vi->has_cvq && 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 (vi->has_cvq && 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));
+
+		dev->hw_features |= NETIF_F_RXHASH;
+	}
+
+	if (vi->has_cvq && 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);
@@ -3180,9 +3367,6 @@ static int virtnet_probe(struct virtio_device *vdev)
 	    virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
 		vi->any_header_sg = true;
 
-	if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
-		vi->has_cvq = true;
-
 	if (virtio_has_feature(vdev, VIRTIO_NET_F_MTU)) {
 		mtu = virtio_cread16(vdev,
 				     offsetof(struct virtio_net_config,
@@ -3254,6 +3438,12 @@ static int virtnet_probe(struct virtio_device *vdev)
 
 	virtnet_set_queues(vi, vi->curr_queue_pairs);
 
+	if (vi->has_rss || vi->has_rss_hash_report) {
+		rtnl_lock();
+		virtnet_init_default_rss(vi);
+		rtnl_unlock();
+	}
+
 	/* Assume link up if device can't report link status,
 	   otherwise get link status from config. */
 	netif_carrier_off(dev);
@@ -3369,7 +3559,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.31.1


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

* [RFC PATCH 2/3] drivers/net/virtio_net: Added basic RSS support.
@ 2021-08-18 17:54   ` Andrew Melnychenko
  0 siblings, 0 replies; 19+ messages in thread
From: Andrew Melnychenko @ 2021-08-18 17:54 UTC (permalink / raw)
  To: mst, jasowang, davem, kuba; +Cc: netdev, 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 | 215 ++++++++++++++++++++++++++++++++++++---
 1 file changed, 203 insertions(+), 12 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 85427b4f51bc..d87bde246305 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -167,6 +167,23 @@ struct receive_queue {
 	struct xdp_rxq_info xdp_rxq;
 };
 
+/* This structure can contain rss message with maximum settings for indirection table and keysize */
+#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 +193,7 @@ struct control_buf {
 	u8 allmulti;
 	__virtio16 vid;
 	__virtio64 offloads;
+	struct virtio_net_ctrl_rss rss;
 };
 
 struct virtnet_info {
@@ -204,6 +222,14 @@ 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;
+	u32 rss_hash_types_supported;
+	u32 rss_hash_types_saved;
+
 	/* Has control virtqueue */
 	bool has_cvq;
 
@@ -393,7 +419,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);
@@ -2171,6 +2199,56 @@ 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 +2473,72 @@ static void virtnet_update_settings(struct virtnet_info *vi)
 		vi->duplex = duplex;
 }
 
+u32 virtnet_get_rxfh_key_size(struct net_device *dev)
+{
+	return ((struct virtnet_info *)netdev_priv(dev))->rss_key_size;
+}
+
+u32 virtnet_get_rxfh_indir_size(struct net_device *dev)
+{
+	return ((struct virtnet_info *)netdev_priv(dev))->rss_indir_table_size;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+		rc = -EOPNOTSUPP;
+	}
+	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 +2554,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)
@@ -2662,6 +2811,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;
 }
 
@@ -3080,13 +3239,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;
@@ -3160,6 +3320,9 @@ static int virtnet_probe(struct virtio_device *vdev)
 
 	INIT_WORK(&vi->config_work, virtnet_config_changed_work);
 
+	if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
+		vi->has_cvq = true;
+
 	/* If we can receive ANY GSO packets, we must allocate large ones. */
 	if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) ||
 	    virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6) ||
@@ -3170,8 +3333,32 @@ 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 (vi->has_cvq && 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 (vi->has_cvq && 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));
+
+		dev->hw_features |= NETIF_F_RXHASH;
+	}
+
+	if (vi->has_cvq && 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);
@@ -3180,9 +3367,6 @@ static int virtnet_probe(struct virtio_device *vdev)
 	    virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
 		vi->any_header_sg = true;
 
-	if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
-		vi->has_cvq = true;
-
 	if (virtio_has_feature(vdev, VIRTIO_NET_F_MTU)) {
 		mtu = virtio_cread16(vdev,
 				     offsetof(struct virtio_net_config,
@@ -3254,6 +3438,12 @@ static int virtnet_probe(struct virtio_device *vdev)
 
 	virtnet_set_queues(vi, vi->curr_queue_pairs);
 
+	if (vi->has_rss || vi->has_rss_hash_report) {
+		rtnl_lock();
+		virtnet_init_default_rss(vi);
+		rtnl_unlock();
+	}
+
 	/* Assume link up if device can't report link status,
 	   otherwise get link status from config. */
 	netif_carrier_off(dev);
@@ -3369,7 +3559,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.31.1

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

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

* [RFC PATCH 3/3] drivers/net/virtio_net: Added RSS hash report.
  2021-08-18 17:54 ` Andrew Melnychenko
@ 2021-08-18 17:54   ` Andrew Melnychenko
  -1 siblings, 0 replies; 19+ messages in thread
From: Andrew Melnychenko @ 2021-08-18 17:54 UTC (permalink / raw)
  To: mst, jasowang, davem, kuba; +Cc: virtualization, netdev, linux-kernel

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 them 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 | 177 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 177 insertions(+)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index d87bde246305..6a52eeaf9292 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -1151,6 +1151,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);
@@ -1177,6 +1179,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;
@@ -2250,6 +2275,132 @@ static void virtnet_init_default_rss(struct virtnet_info *vi)
 	netdev_rss_key_fill(vi->ctrl->rss.key, vi->rss_key_size);
 }
 
+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;
+	}
+}
+
+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)
 {
@@ -2530,8 +2681,28 @@ int virtnet_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, u32 *r
 	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;
 	}
@@ -2559,6 +2730,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)
@@ -3351,8 +3523,13 @@ static int virtnet_probe(struct virtio_device *vdev)
 	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;
+		dev->features |= NETIF_F_NTUPLE;
 	}
 
 	if (vi->has_cvq && vi->has_rss_hash_report)
-- 
2.31.1


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

* [RFC PATCH 3/3] drivers/net/virtio_net: Added RSS hash report.
@ 2021-08-18 17:54   ` Andrew Melnychenko
  0 siblings, 0 replies; 19+ messages in thread
From: Andrew Melnychenko @ 2021-08-18 17:54 UTC (permalink / raw)
  To: mst, jasowang, davem, kuba; +Cc: netdev, 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 them 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 | 177 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 177 insertions(+)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index d87bde246305..6a52eeaf9292 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -1151,6 +1151,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);
@@ -1177,6 +1179,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;
@@ -2250,6 +2275,132 @@ static void virtnet_init_default_rss(struct virtnet_info *vi)
 	netdev_rss_key_fill(vi->ctrl->rss.key, vi->rss_key_size);
 }
 
+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;
+	}
+}
+
+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)
 {
@@ -2530,8 +2681,28 @@ int virtnet_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, u32 *r
 	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;
 	}
@@ -2559,6 +2730,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)
@@ -3351,8 +3523,13 @@ static int virtnet_probe(struct virtio_device *vdev)
 	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;
+		dev->features |= NETIF_F_NTUPLE;
 	}
 
 	if (vi->has_cvq && vi->has_rss_hash_report)
-- 
2.31.1

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

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

* Re: [RFC PATCH 3/3] drivers/net/virtio_net: Added RSS hash report.
  2021-08-18 17:54   ` Andrew Melnychenko
  (?)
@ 2021-08-18 21:33   ` kernel test robot
  -1 siblings, 0 replies; 19+ messages in thread
From: kernel test robot @ 2021-08-18 21:33 UTC (permalink / raw)
  To: kbuild-all

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

Hi Andrew,

[FYI, it's a private test report for your RFC patch.]
[auto build test WARNING on vhost/linux-next]
[also build test WARNING on net-next/master net/master linus/master sparc-next/master v5.14-rc6 next-20210818]
[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/drivers-net-virtio_net-Added-RSS-support/20210819-015744
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost.git linux-next
config: i386-randconfig-s001-20210818 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
reproduce:
        # apt-get install sparse
        # sparse version: v0.6.3-348-gf0e6938b-dirty
        # https://github.com/0day-ci/linux/commit/2205ca0b751f734cf3ea53258d9b8e3f3849fe16
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Andrew-Melnychenko/drivers-net-virtio_net-Added-RSS-support/20210819-015744
        git checkout 2205ca0b751f734cf3ea53258d9b8e3f3849fe16
        # save the attached .config to linux build tree
        make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=i386 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:2278:6: sparse: sparse: symbol 'virtnet_get_hashflow' was not declared. Should it be static?
>> 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:2330:6: sparse: sparse: symbol 'virtnet_set_hashflow' was not declared. Should it be static?
>> drivers/net/virtio_net.c:2627:5: sparse: sparse: symbol 'virtnet_get_rxfh_key_size' was not declared. Should it be static?
>> drivers/net/virtio_net.c:2632:5: sparse: sparse: symbol 'virtnet_get_rxfh_indir_size' was not declared. Should it be static?
>> drivers/net/virtio_net.c:2637:5: sparse: sparse: symbol 'virtnet_get_rxfh' was not declared. Should it be static?
>> drivers/net/virtio_net.c:2656:5: sparse: sparse: symbol 'virtnet_set_rxfh' was not declared. Should it be static?
>> drivers/net/virtio_net.c:2676:5: sparse: sparse: symbol 'virtnet_get_rxnfc' was not declared. Should it be static?
   drivers/net/virtio_net.c:2988: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:2988:61: sparse:     expected restricted __le32 [usertype] hash_types
   drivers/net/virtio_net.c:2988:61: sparse:     got unsigned int [usertype] rss_hash_types_saved

Please review and possibly fold the followup patch.

vim +1185 drivers/net/virtio_net.c

  1145	
  1146	static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
  1147				void *buf, unsigned int len, void **ctx,
  1148				unsigned int *xdp_xmit,
  1149				struct virtnet_rq_stats *stats)
  1150	{
  1151		struct net_device *dev = vi->dev;
  1152		struct sk_buff *skb;
  1153		struct virtio_net_hdr_mrg_rxbuf *hdr;
  1154		struct virtio_net_hdr_v1_hash *hdr_hash;
  1155		enum pkt_hash_types rss_hash_type;
  1156	
  1157		if (unlikely(len < vi->hdr_len + ETH_HLEN)) {
  1158			pr_debug("%s: short packet %i\n", dev->name, len);
  1159			dev->stats.rx_length_errors++;
  1160			if (vi->mergeable_rx_bufs) {
  1161				put_page(virt_to_head_page(buf));
  1162			} else if (vi->big_packets) {
  1163				give_pages(rq, buf);
  1164			} else {
  1165				put_page(virt_to_head_page(buf));
  1166			}
  1167			return;
  1168		}
  1169	
  1170		if (vi->mergeable_rx_bufs)
  1171			skb = receive_mergeable(dev, vi, rq, buf, ctx, len, xdp_xmit,
  1172						stats);
  1173		else if (vi->big_packets)
  1174			skb = receive_big(dev, vi, rq, buf, len, stats);
  1175		else
  1176			skb = receive_small(dev, vi, rq, buf, ctx, len, xdp_xmit, stats);
  1177	
  1178		if (unlikely(!skb))
  1179			return;
  1180	
  1181		hdr = skb_vnet_hdr(skb);
  1182		if (vi->has_rss_hash_report && (dev->features & NETIF_F_RXHASH)) {
  1183			hdr_hash = (struct virtio_net_hdr_v1_hash *)(hdr);
  1184	
> 1185			switch (hdr_hash->hash_report) {
  1186			case VIRTIO_NET_HASH_REPORT_TCPv4:
  1187			case VIRTIO_NET_HASH_REPORT_UDPv4:
  1188			case VIRTIO_NET_HASH_REPORT_TCPv6:
  1189			case VIRTIO_NET_HASH_REPORT_UDPv6:
  1190			case VIRTIO_NET_HASH_REPORT_TCPv6_EX:
  1191			case VIRTIO_NET_HASH_REPORT_UDPv6_EX:
  1192				rss_hash_type = PKT_HASH_TYPE_L4;
  1193				break;
  1194			case VIRTIO_NET_HASH_REPORT_IPv4:
  1195			case VIRTIO_NET_HASH_REPORT_IPv6:
  1196			case VIRTIO_NET_HASH_REPORT_IPv6_EX:
  1197				rss_hash_type = PKT_HASH_TYPE_L3;
  1198				break;
  1199			case VIRTIO_NET_HASH_REPORT_NONE:
  1200			default:
  1201				rss_hash_type = PKT_HASH_TYPE_NONE;
  1202			}
> 1203			skb_set_hash(skb, hdr_hash->hash_value, rss_hash_type);
  1204		}
  1205	
  1206		if (hdr->hdr.flags & VIRTIO_NET_HDR_F_DATA_VALID)
  1207			skb->ip_summed = CHECKSUM_UNNECESSARY;
  1208	
  1209		if (virtio_net_hdr_to_skb(skb, &hdr->hdr,
  1210					  virtio_is_little_endian(vi->vdev))) {
  1211			net_warn_ratelimited("%s: bad gso: type: %u, size: %u\n",
  1212					     dev->name, hdr->hdr.gso_type,
  1213					     hdr->hdr.gso_size);
  1214			goto frame_err;
  1215		}
  1216	
  1217		skb_record_rx_queue(skb, vq2rxq(rq->vq));
  1218		skb->protocol = eth_type_trans(skb, dev);
  1219		pr_debug("Receiving skb proto 0x%04x len %i type %i\n",
  1220			 ntohs(skb->protocol), skb->len, skb->pkt_type);
  1221	
  1222		napi_gro_receive(&rq->napi, skb);
  1223		return;
  1224	
  1225	frame_err:
  1226		dev->stats.rx_frame_errors++;
  1227		dev_kfree_skb(skb);
  1228	}
  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: 29846 bytes --]

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

* [RFC PATCH] drivers/net/virtio_net: virtnet_get_hashflow() can be static
  2021-08-18 17:54   ` Andrew Melnychenko
  (?)
  (?)
@ 2021-08-18 21:33   ` kernel test robot
  -1 siblings, 0 replies; 19+ messages in thread
From: kernel test robot @ 2021-08-18 21:33 UTC (permalink / raw)
  To: kbuild-all

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

drivers/net/virtio_net.c:2278:6: warning: symbol 'virtnet_get_hashflow' was not declared. Should it be static?
drivers/net/virtio_net.c:2330:6: warning: symbol 'virtnet_set_hashflow' was not declared. Should it be static?
drivers/net/virtio_net.c:2627:5: warning: symbol 'virtnet_get_rxfh_key_size' was not declared. Should it be static?
drivers/net/virtio_net.c:2632:5: warning: symbol 'virtnet_get_rxfh_indir_size' was not declared. Should it be static?
drivers/net/virtio_net.c:2637:5: warning: symbol 'virtnet_get_rxfh' was not declared. Should it be static?
drivers/net/virtio_net.c:2656:5: warning: symbol 'virtnet_set_rxfh' was not declared. Should it be static?
drivers/net/virtio_net.c:2676:5: warning: symbol 'virtnet_get_rxnfc' was not declared. Should it be static?

Reported-by: kernel test robot <lkp@intel.com>
Signed-off-by: kernel test robot <lkp@intel.com>
---
 virtio_net.c |   14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 6a52eeaf929289..ea8f9c4050ffa8 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -2275,7 +2275,7 @@ static void virtnet_init_default_rss(struct virtnet_info *vi)
 	netdev_rss_key_fill(vi->ctrl->rss.key, vi->rss_key_size);
 }
 
-void virtnet_get_hashflow(const struct virtnet_info *vi, struct ethtool_rxnfc *info)
+static void virtnet_get_hashflow(const struct virtnet_info *vi, struct ethtool_rxnfc *info)
 {
 	info->data = 0;
 	switch (info->flow_type) {
@@ -2327,7 +2327,7 @@ void virtnet_get_hashflow(const struct virtnet_info *vi, struct ethtool_rxnfc *i
 	}
 }
 
-bool virtnet_set_hashflow(struct virtnet_info *vi, struct ethtool_rxnfc *info)
+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);
@@ -2624,17 +2624,17 @@ static void virtnet_update_settings(struct virtnet_info *vi)
 		vi->duplex = duplex;
 }
 
-u32 virtnet_get_rxfh_key_size(struct net_device *dev)
+static u32 virtnet_get_rxfh_key_size(struct net_device *dev)
 {
 	return ((struct virtnet_info *)netdev_priv(dev))->rss_key_size;
 }
 
-u32 virtnet_get_rxfh_indir_size(struct net_device *dev)
+static u32 virtnet_get_rxfh_indir_size(struct net_device *dev)
 {
 	return ((struct virtnet_info *)netdev_priv(dev))->rss_indir_table_size;
 }
 
-int virtnet_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc)
+static int virtnet_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc)
 {
 	struct virtnet_info *vi = netdev_priv(dev);
 	int i;
@@ -2653,7 +2653,7 @@ int virtnet_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc)
 	return 0;
 }
 
-int virtnet_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key, const u8 hfunc)
+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;
@@ -2673,7 +2673,7 @@ int virtnet_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key, co
 	return 0;
 }
 
-int virtnet_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, u32 *rule_locs)
+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;

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

* Re: [RFC PATCH 2/3] drivers/net/virtio_net: Added basic RSS support.
  2021-08-18 17:54   ` Andrew Melnychenko
  (?)
@ 2021-08-18 22:38   ` kernel test robot
  -1 siblings, 0 replies; 19+ messages in thread
From: kernel test robot @ 2021-08-18 22:38 UTC (permalink / raw)
  To: kbuild-all

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

Hi Andrew,

[FYI, it's a private test report for your RFC patch.]
[auto build test WARNING on vhost/linux-next]
[also build test WARNING on net-next/master net/master linus/master v5.14-rc6 next-20210818]
[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/drivers-net-virtio_net-Added-RSS-support/20210819-015744
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost.git linux-next
config: i386-randconfig-a015-20210818 (attached as .config)
compiler: clang version 14.0.0 (https://github.com/llvm/llvm-project d2b574a4dea5b718e4386bf2e26af0126e5978ce)
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/e731fc592ef2151e3a1fe044fa182517adb1e47e
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Andrew-Melnychenko/drivers-net-virtio_net-Added-RSS-support/20210819-015744
        git checkout e731fc592ef2151e3a1fe044fa182517adb1e47e
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=i386 

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

All warnings (new ones prefixed by >>):

>> drivers/net/virtio_net.c:2476:5: warning: no previous prototype for function 'virtnet_get_rxfh_key_size' [-Wmissing-prototypes]
   u32 virtnet_get_rxfh_key_size(struct net_device *dev)
       ^
   drivers/net/virtio_net.c:2476:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   u32 virtnet_get_rxfh_key_size(struct net_device *dev)
   ^
   static 
>> drivers/net/virtio_net.c:2481:5: warning: no previous prototype for function 'virtnet_get_rxfh_indir_size' [-Wmissing-prototypes]
   u32 virtnet_get_rxfh_indir_size(struct net_device *dev)
       ^
   drivers/net/virtio_net.c:2481:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   u32 virtnet_get_rxfh_indir_size(struct net_device *dev)
   ^
   static 
>> drivers/net/virtio_net.c:2486:5: warning: no previous prototype for function 'virtnet_get_rxfh' [-Wmissing-prototypes]
   int virtnet_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc)
       ^
   drivers/net/virtio_net.c:2486:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int virtnet_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc)
   ^
   static 
>> drivers/net/virtio_net.c:2505:5: warning: no previous prototype for function 'virtnet_set_rxfh' [-Wmissing-prototypes]
   int virtnet_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key, const u8 hfunc)
       ^
   drivers/net/virtio_net.c:2505:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int virtnet_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key, const u8 hfunc)
   ^
   static 
   drivers/net/virtio_net.c:2535:2: error: 'default' statement not in switch statement
           default:
           ^
>> drivers/net/virtio_net.c:2525:5: warning: no previous prototype for function 'virtnet_get_rxnfc' [-Wmissing-prototypes]
   int virtnet_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, u32 *rule_locs)
       ^
   drivers/net/virtio_net.c:2525:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int virtnet_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, u32 *rule_locs)
   ^
   static 
   drivers/net/virtio_net.c:2539:2: error: expected identifier or '('
           return rc;
           ^
   drivers/net/virtio_net.c:2540:1: error: extraneous closing brace ('}')
   }
   ^
   5 warnings and 3 errors generated.


vim +/virtnet_get_rxfh_key_size +2476 drivers/net/virtio_net.c

  2475	
> 2476	u32 virtnet_get_rxfh_key_size(struct net_device *dev)
  2477	{
  2478		return ((struct virtnet_info *)netdev_priv(dev))->rss_key_size;
  2479	}
  2480	
> 2481	u32 virtnet_get_rxfh_indir_size(struct net_device *dev)
  2482	{
  2483		return ((struct virtnet_info *)netdev_priv(dev))->rss_indir_table_size;
  2484	}
  2485	
> 2486	int virtnet_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc)
  2487	{
  2488		struct virtnet_info *vi = netdev_priv(dev);
  2489		int i;
  2490	
  2491		if (indir) {
  2492			for (i = 0; i < vi->rss_indir_table_size; ++i)
  2493				indir[i] = vi->ctrl->rss.indirection_table[i];
  2494		}
  2495	
  2496		if (key)
  2497			memcpy(key, vi->ctrl->rss.key, vi->rss_key_size);
  2498	
  2499		if (hfunc)
  2500			*hfunc = ETH_RSS_HASH_TOP;
  2501	
  2502		return 0;
  2503	}
  2504	
> 2505	int virtnet_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key, const u8 hfunc)
  2506	{
  2507		struct virtnet_info *vi = netdev_priv(dev);
  2508		int i;
  2509	
  2510		if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
  2511			return -EOPNOTSUPP;
  2512	
  2513		if (indir) {
  2514			for (i = 0; i < vi->rss_indir_table_size; ++i)
  2515				vi->ctrl->rss.indirection_table[i] = indir[i];
  2516		}
  2517		if (key)
  2518			memcpy(vi->ctrl->rss.key, key, vi->rss_key_size);
  2519	
  2520		virtnet_commit_rss_command(vi);
  2521	
  2522		return 0;
  2523	}
  2524	
> 2525	int virtnet_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, u32 *rule_locs)
  2526	{
  2527		struct virtnet_info *vi = netdev_priv(dev);
  2528		int rc = 0;
  2529	
  2530		switch (info->cmd) {
  2531		case ETHTOOL_GRXRINGS:
  2532			info->data = vi->curr_queue_pairs;
  2533			rc = -EOPNOTSUPP;
  2534		}
  2535		default:
  2536			rc = -EOPNOTSUPP;
  2537		}
  2538	
  2539		return rc;
  2540	}
  2541	

---
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: 33204 bytes --]

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

* Re: [RFC PATCH 3/3] drivers/net/virtio_net: Added RSS hash report.
  2021-08-18 17:54   ` Andrew Melnychenko
                     ` (2 preceding siblings ...)
  (?)
@ 2021-08-19  0:48   ` kernel test robot
  -1 siblings, 0 replies; 19+ messages in thread
From: kernel test robot @ 2021-08-19  0:48 UTC (permalink / raw)
  To: kbuild-all

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

Hi Andrew,

[FYI, it's a private test report for your RFC patch.]
[auto build test WARNING on vhost/linux-next]
[also build test WARNING on net-next/master net/master linus/master v5.14-rc6 next-20210818]
[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/drivers-net-virtio_net-Added-RSS-support/20210819-015744
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost.git linux-next
config: i386-randconfig-a015-20210818 (attached as .config)
compiler: clang version 14.0.0 (https://github.com/llvm/llvm-project d2b574a4dea5b718e4386bf2e26af0126e5978ce)
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/2205ca0b751f734cf3ea53258d9b8e3f3849fe16
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Andrew-Melnychenko/drivers-net-virtio_net-Added-RSS-support/20210819-015744
        git checkout 2205ca0b751f734cf3ea53258d9b8e3f3849fe16
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=i386 

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

All warnings (new ones prefixed by >>):

>> drivers/net/virtio_net.c:2278:6: warning: no previous prototype for function 'virtnet_get_hashflow' [-Wmissing-prototypes]
   void virtnet_get_hashflow(const struct virtnet_info *vi, struct ethtool_rxnfc *info)
        ^
   drivers/net/virtio_net.c:2278:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   void virtnet_get_hashflow(const struct virtnet_info *vi, struct ethtool_rxnfc *info)
   ^
   static 
>> drivers/net/virtio_net.c:2330:6: warning: no previous prototype for function 'virtnet_set_hashflow' [-Wmissing-prototypes]
   bool virtnet_set_hashflow(struct virtnet_info *vi, struct ethtool_rxnfc *info)
        ^
   drivers/net/virtio_net.c:2330:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   bool virtnet_set_hashflow(struct virtnet_info *vi, struct ethtool_rxnfc *info)
   ^
   static 
   drivers/net/virtio_net.c:2627:5: warning: no previous prototype for function 'virtnet_get_rxfh_key_size' [-Wmissing-prototypes]
   u32 virtnet_get_rxfh_key_size(struct net_device *dev)
       ^
   drivers/net/virtio_net.c:2627:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   u32 virtnet_get_rxfh_key_size(struct net_device *dev)
   ^
   static 
   drivers/net/virtio_net.c:2632:5: warning: no previous prototype for function 'virtnet_get_rxfh_indir_size' [-Wmissing-prototypes]
   u32 virtnet_get_rxfh_indir_size(struct net_device *dev)
       ^
   drivers/net/virtio_net.c:2632:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   u32 virtnet_get_rxfh_indir_size(struct net_device *dev)
   ^
   static 
   drivers/net/virtio_net.c:2637:5: warning: no previous prototype for function 'virtnet_get_rxfh' [-Wmissing-prototypes]
   int virtnet_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc)
       ^
   drivers/net/virtio_net.c:2637:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int virtnet_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc)
   ^
   static 
   drivers/net/virtio_net.c:2656:5: warning: no previous prototype for function 'virtnet_set_rxfh' [-Wmissing-prototypes]
   int virtnet_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key, const u8 hfunc)
       ^
   drivers/net/virtio_net.c:2656:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int virtnet_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key, const u8 hfunc)
   ^
   static 
   drivers/net/virtio_net.c:2676:5: warning: no previous prototype for function 'virtnet_get_rxnfc' [-Wmissing-prototypes]
   int virtnet_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, u32 *rule_locs)
       ^
   drivers/net/virtio_net.c:2676:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int virtnet_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, u32 *rule_locs)
   ^
   static 
   7 warnings generated.


vim +/virtnet_get_hashflow +2278 drivers/net/virtio_net.c

  2277	
> 2278	void virtnet_get_hashflow(const struct virtnet_info *vi, struct ethtool_rxnfc *info)
  2279	{
  2280		info->data = 0;
  2281		switch (info->flow_type) {
  2282		case TCP_V4_FLOW:
  2283			if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_TCPv4) {
  2284				info->data = RXH_IP_SRC | RXH_IP_DST |
  2285							 RXH_L4_B_0_1 | RXH_L4_B_2_3;
  2286			} else if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv4) {
  2287				info->data = RXH_IP_SRC | RXH_IP_DST;
  2288			}
  2289			break;
  2290		case TCP_V6_FLOW:
  2291			if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_TCPv6) {
  2292				info->data = RXH_IP_SRC | RXH_IP_DST |
  2293							 RXH_L4_B_0_1 | RXH_L4_B_2_3;
  2294			} else if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv6) {
  2295				info->data = RXH_IP_SRC | RXH_IP_DST;
  2296			}
  2297			break;
  2298		case UDP_V4_FLOW:
  2299			if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_UDPv4) {
  2300				info->data = RXH_IP_SRC | RXH_IP_DST |
  2301							 RXH_L4_B_0_1 | RXH_L4_B_2_3;
  2302			} else if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv4) {
  2303				info->data = RXH_IP_SRC | RXH_IP_DST;
  2304			}
  2305			break;
  2306		case UDP_V6_FLOW:
  2307			if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_UDPv6) {
  2308				info->data = RXH_IP_SRC | RXH_IP_DST |
  2309							 RXH_L4_B_0_1 | RXH_L4_B_2_3;
  2310			} else if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv6) {
  2311				info->data = RXH_IP_SRC | RXH_IP_DST;
  2312			}
  2313			break;
  2314		case IPV4_FLOW:
  2315			if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv4)
  2316				info->data = RXH_IP_SRC | RXH_IP_DST;
  2317	
  2318			break;
  2319		case IPV6_FLOW:
  2320			if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv4)
  2321				info->data = RXH_IP_SRC | RXH_IP_DST;
  2322	
  2323			break;
  2324		default:
  2325			info->data = 0;
  2326			break;
  2327		}
  2328	}
  2329	
> 2330	bool virtnet_set_hashflow(struct virtnet_info *vi, struct ethtool_rxnfc *info)
  2331	{
  2332		u64 is_iphash = info->data & (RXH_IP_SRC | RXH_IP_DST);
  2333		u64 is_porthash = info->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3);
  2334		u32 new_hashtypes = vi->rss_hash_types_saved;
  2335	
  2336		if ((is_iphash && (is_iphash != (RXH_IP_SRC | RXH_IP_DST))) ||
  2337		    (is_porthash && (is_porthash != (RXH_L4_B_0_1 | RXH_L4_B_2_3)))) {
  2338			return false;
  2339		}
  2340	
  2341		if (!is_iphash && is_porthash)
  2342			return false;
  2343	
  2344		switch (info->flow_type) {
  2345		case TCP_V4_FLOW:
  2346		case UDP_V4_FLOW:
  2347		case IPV4_FLOW:
  2348			new_hashtypes &= ~VIRTIO_NET_RSS_HASH_TYPE_IPv4;
  2349			if (is_iphash)
  2350				new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_IPv4;
  2351	
  2352			break;
  2353		case TCP_V6_FLOW:
  2354		case UDP_V6_FLOW:
  2355		case IPV6_FLOW:
  2356			new_hashtypes &= ~VIRTIO_NET_RSS_HASH_TYPE_IPv6;
  2357			if (is_iphash)
  2358				new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_IPv6;
  2359	
  2360			break;
  2361		default:
  2362			break;
  2363		}
  2364	
  2365		switch (info->flow_type) {
  2366		case TCP_V4_FLOW:
  2367			new_hashtypes &= ~VIRTIO_NET_RSS_HASH_TYPE_TCPv4;
  2368			if (is_porthash)
  2369				new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_TCPv4;
  2370	
  2371			break;
  2372		case UDP_V4_FLOW:
  2373			new_hashtypes &= ~VIRTIO_NET_RSS_HASH_TYPE_UDPv4;
  2374			if (is_porthash)
  2375				new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_UDPv4;
  2376	
  2377			break;
  2378		case TCP_V6_FLOW:
  2379			new_hashtypes &= ~VIRTIO_NET_RSS_HASH_TYPE_TCPv6;
  2380			if (is_porthash)
  2381				new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_TCPv6;
  2382	
  2383			break;
  2384		case UDP_V6_FLOW:
  2385			new_hashtypes &= ~VIRTIO_NET_RSS_HASH_TYPE_UDPv6;
  2386			if (is_porthash)
  2387				new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_UDPv6;
  2388	
  2389			break;
  2390		default:
  2391			break;
  2392		}
  2393	
  2394		if (new_hashtypes != vi->rss_hash_types_saved) {
  2395			vi->rss_hash_types_saved = new_hashtypes;
  2396			vi->ctrl->rss.table_info.hash_types = vi->rss_hash_types_saved;
  2397			if (vi->dev->features & NETIF_F_RXHASH)
  2398				return virtnet_commit_rss_command(vi);
  2399		}
  2400	
  2401		return true;
  2402	}
  2403	

---
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: 33204 bytes --]

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

* Re: [RFC PATCH 0/3] drivers/net/virtio_net: Added RSS support.
  2021-08-18 17:54 ` Andrew Melnychenko
                   ` (3 preceding siblings ...)
  (?)
@ 2021-08-31 12:10 ` Andrew Melnichenko
  -1 siblings, 0 replies; 19+ messages in thread
From: Andrew Melnichenko @ 2021-08-31 12:10 UTC (permalink / raw)
  To: Michael S. Tsirkin, Jason Wang, davem, kuba
  Cc: Yan Vugenfirer, netdev, Yuri Benditovich, linux-kernel, virtualization


[-- Attachment #1.1: Type: text/plain, Size: 1022 bytes --]

Hi guys,
Can you please review possible virtio-net driver RSS support?
Do you have any comments or proposals?

On Wed, Aug 18, 2021 at 8:55 PM Andrew Melnychenko <andrew@daynix.com>
wrote:

> 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.
>
> Andrew Melnychenko (3):
>   drivers/net/virtio_net: Fixed vheader to use v1.
>   drivers/net/virtio_net: Added basic RSS support.
>   drivers/net/virtio_net: Added RSS hash report.
>
>  drivers/net/virtio_net.c | 402 +++++++++++++++++++++++++++++++++++++--
>  1 file changed, 385 insertions(+), 17 deletions(-)
>
> --
> 2.31.1
>
>

[-- Attachment #1.2: Type: text/html, Size: 1451 bytes --]

[-- Attachment #2: Type: text/plain, Size: 183 bytes --]

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

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

* Re: [RFC PATCH 1/3] drivers/net/virtio_net: Fixed vheader to use v1.
  2021-08-18 17:54   ` Andrew Melnychenko
@ 2021-09-01  6:52     ` Jason Wang
  -1 siblings, 0 replies; 19+ messages in thread
From: Jason Wang @ 2021-09-01  6:52 UTC (permalink / raw)
  To: Andrew Melnychenko, mst, davem, kuba; +Cc: virtualization, netdev, linux-kernel


在 2021/8/19 上午1:54, Andrew Melnychenko 写道:
> 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 | 10 +++++-----
>   1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index 56c3f8519093..85427b4f51bc 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];
>   };


So we had:

         if (vi->mergeable_rx_bufs)
                 hdr_padded_len = sizeof(*hdr);
         else
                 hdr_padded_len = sizeof(struct padded_vnet_hdr);

I wonder if it's better to add one ore condition for the hash header 
instead of enforcing it even if it was not negotiated.


>   
>   static bool is_xdp_frame(void *ptr)
> @@ -1258,7 +1258,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)
> @@ -1642,7 +1642,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;


Looks like an unnecessary change.


>   	bool can_push;
>   
>   	pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest);
> @@ -2819,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;


I think the change here and get_mergeable_buf_len() should be a separate 
patch.

Thanks


>   	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;


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

* Re: [RFC PATCH 1/3] drivers/net/virtio_net: Fixed vheader to use v1.
@ 2021-09-01  6:52     ` Jason Wang
  0 siblings, 0 replies; 19+ messages in thread
From: Jason Wang @ 2021-09-01  6:52 UTC (permalink / raw)
  To: Andrew Melnychenko, mst, davem, kuba; +Cc: netdev, linux-kernel, virtualization


在 2021/8/19 上午1:54, Andrew Melnychenko 写道:
> 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 | 10 +++++-----
>   1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index 56c3f8519093..85427b4f51bc 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];
>   };


So we had:

         if (vi->mergeable_rx_bufs)
                 hdr_padded_len = sizeof(*hdr);
         else
                 hdr_padded_len = sizeof(struct padded_vnet_hdr);

I wonder if it's better to add one ore condition for the hash header 
instead of enforcing it even if it was not negotiated.


>   
>   static bool is_xdp_frame(void *ptr)
> @@ -1258,7 +1258,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)
> @@ -1642,7 +1642,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;


Looks like an unnecessary change.


>   	bool can_push;
>   
>   	pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest);
> @@ -2819,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;


I think the change here and get_mergeable_buf_len() should be a separate 
patch.

Thanks


>   	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;

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

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

* Re: [RFC PATCH 2/3] drivers/net/virtio_net: Added basic RSS support.
  2021-08-18 17:54   ` Andrew Melnychenko
@ 2021-09-01  7:35     ` Jason Wang
  -1 siblings, 0 replies; 19+ messages in thread
From: Jason Wang @ 2021-09-01  7:35 UTC (permalink / raw)
  To: Andrew Melnychenko
  Cc: mst, davem, Jakub Kicinski, virtualization, netdev, linux-kernel

On Thu, Aug 19, 2021 at 1:55 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 | 215 ++++++++++++++++++++++++++++++++++++---
>  1 file changed, 203 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index 85427b4f51bc..d87bde246305 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -167,6 +167,23 @@ struct receive_queue {
>         struct xdp_rxq_info xdp_rxq;
>  };
>
> +/* This structure can contain rss message with maximum settings for indirection table and keysize */
> +#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];
> +};


Any reason that those doesn't belong to uAPI?

And spec said:

"

The device MUST set rss_max_key_size to at least 40, if it offers
VIRTIO_NET_F_RSS or VIRTIO_NET_F_HASH_REPORT.

The device MUST set rss_max_indirection_table_length to at least 128,
if it offers VIRTIO_NET_F_RSS.

"

But it looks to me that you define those as maximum size instead of
minimum size?

> +
>  /* Control VQ buffers: protected by the rtnl lock */
>  struct control_buf {
>         struct virtio_net_ctrl_hdr hdr;
> @@ -176,6 +193,7 @@ struct control_buf {
>         u8 allmulti;
>         __virtio16 vid;
>         __virtio64 offloads;
> +       struct virtio_net_ctrl_rss rss;
>  };
>
>  struct virtnet_info {
> @@ -204,6 +222,14 @@ 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;
> +       u32 rss_hash_types_supported;
> +       u32 rss_hash_types_saved;
> +
>         /* Has control virtqueue */
>         bool has_cvq;
>
> @@ -393,7 +419,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);

I don't get here. You change the padder_vnet_hdr but here it was only
used for !non-mergeable ?


> @@ -2171,6 +2199,56 @@ 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 +2473,72 @@ static void virtnet_update_settings(struct virtnet_info *vi)
>                 vi->duplex = duplex;
>  }
>
> +u32 virtnet_get_rxfh_key_size(struct net_device *dev)
> +{
> +       return ((struct virtnet_info *)netdev_priv(dev))->rss_key_size;
> +}
> +
> +u32 virtnet_get_rxfh_indir_size(struct net_device *dev)
> +{
> +       return ((struct virtnet_info *)netdev_priv(dev))->rss_indir_table_size;
> +}
> +
> +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;
> +}
> +
> +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;
> +}
> +
> +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;
> +               rc = -EOPNOTSUPP;
> +       }
> +       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 +2554,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)
> @@ -2662,6 +2811,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;
>  }
>
> @@ -3080,13 +3239,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));

I think virtio_cread_features() can still work here, or am I missing anything?

>
>         /* 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;
> @@ -3160,6 +3320,9 @@ static int virtnet_probe(struct virtio_device *vdev)
>
>         INIT_WORK(&vi->config_work, virtnet_config_changed_work);
>
> +       if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
> +               vi->has_cvq = true;
> +
>         /* If we can receive ANY GSO packets, we must allocate large ones. */
>         if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) ||
>             virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6) ||
> @@ -3170,8 +3333,32 @@ 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 (vi->has_cvq && virtio_has_feature(vdev, VIRTIO_NET_F_HASH_REPORT)) {

Let's add a new validation in virtnet_validate_features(), then
there's no need for the check of cvq here (and the moving of the
has_cvq assignment).


> +               vi->has_rss_hash_report = true;
> +               vi->rss_indir_table_size = 1;
> +               vi->rss_key_size = VIRTIO_NET_RSS_MAX_KEY_SIZE;
> +       }
> +
> +       if (vi->has_cvq && 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));
> +
> +               dev->hw_features |= NETIF_F_RXHASH;
> +       }
> +
> +       if (vi->has_cvq && 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);
> @@ -3180,9 +3367,6 @@ static int virtnet_probe(struct virtio_device *vdev)
>             virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
>                 vi->any_header_sg = true;
>
> -       if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
> -               vi->has_cvq = true;
> -
>         if (virtio_has_feature(vdev, VIRTIO_NET_F_MTU)) {
>                 mtu = virtio_cread16(vdev,
>                                      offsetof(struct virtio_net_config,
> @@ -3254,6 +3438,12 @@ static int virtnet_probe(struct virtio_device *vdev)
>
>         virtnet_set_queues(vi, vi->curr_queue_pairs);
>
> +       if (vi->has_rss || vi->has_rss_hash_report) {
> +               rtnl_lock();
> +               virtnet_init_default_rss(vi);
> +               rtnl_unlock();
> +       }

I wonder what happens if the user sets a new RSS before this?

Thanks


> +
>         /* Assume link up if device can't report link status,
>            otherwise get link status from config. */
>         netif_carrier_off(dev);
> @@ -3369,7 +3559,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.31.1
>


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

* Re: [RFC PATCH 2/3] drivers/net/virtio_net: Added basic RSS support.
@ 2021-09-01  7:35     ` Jason Wang
  0 siblings, 0 replies; 19+ messages in thread
From: Jason Wang @ 2021-09-01  7:35 UTC (permalink / raw)
  To: Andrew Melnychenko
  Cc: mst, netdev, linux-kernel, virtualization, Jakub Kicinski, davem

On Thu, Aug 19, 2021 at 1:55 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 | 215 ++++++++++++++++++++++++++++++++++++---
>  1 file changed, 203 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index 85427b4f51bc..d87bde246305 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -167,6 +167,23 @@ struct receive_queue {
>         struct xdp_rxq_info xdp_rxq;
>  };
>
> +/* This structure can contain rss message with maximum settings for indirection table and keysize */
> +#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];
> +};


Any reason that those doesn't belong to uAPI?

And spec said:

"

The device MUST set rss_max_key_size to at least 40, if it offers
VIRTIO_NET_F_RSS or VIRTIO_NET_F_HASH_REPORT.

The device MUST set rss_max_indirection_table_length to at least 128,
if it offers VIRTIO_NET_F_RSS.

"

But it looks to me that you define those as maximum size instead of
minimum size?

> +
>  /* Control VQ buffers: protected by the rtnl lock */
>  struct control_buf {
>         struct virtio_net_ctrl_hdr hdr;
> @@ -176,6 +193,7 @@ struct control_buf {
>         u8 allmulti;
>         __virtio16 vid;
>         __virtio64 offloads;
> +       struct virtio_net_ctrl_rss rss;
>  };
>
>  struct virtnet_info {
> @@ -204,6 +222,14 @@ 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;
> +       u32 rss_hash_types_supported;
> +       u32 rss_hash_types_saved;
> +
>         /* Has control virtqueue */
>         bool has_cvq;
>
> @@ -393,7 +419,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);

I don't get here. You change the padder_vnet_hdr but here it was only
used for !non-mergeable ?


> @@ -2171,6 +2199,56 @@ 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 +2473,72 @@ static void virtnet_update_settings(struct virtnet_info *vi)
>                 vi->duplex = duplex;
>  }
>
> +u32 virtnet_get_rxfh_key_size(struct net_device *dev)
> +{
> +       return ((struct virtnet_info *)netdev_priv(dev))->rss_key_size;
> +}
> +
> +u32 virtnet_get_rxfh_indir_size(struct net_device *dev)
> +{
> +       return ((struct virtnet_info *)netdev_priv(dev))->rss_indir_table_size;
> +}
> +
> +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;
> +}
> +
> +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;
> +}
> +
> +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;
> +               rc = -EOPNOTSUPP;
> +       }
> +       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 +2554,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)
> @@ -2662,6 +2811,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;
>  }
>
> @@ -3080,13 +3239,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));

I think virtio_cread_features() can still work here, or am I missing anything?

>
>         /* 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;
> @@ -3160,6 +3320,9 @@ static int virtnet_probe(struct virtio_device *vdev)
>
>         INIT_WORK(&vi->config_work, virtnet_config_changed_work);
>
> +       if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
> +               vi->has_cvq = true;
> +
>         /* If we can receive ANY GSO packets, we must allocate large ones. */
>         if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) ||
>             virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6) ||
> @@ -3170,8 +3333,32 @@ 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 (vi->has_cvq && virtio_has_feature(vdev, VIRTIO_NET_F_HASH_REPORT)) {

Let's add a new validation in virtnet_validate_features(), then
there's no need for the check of cvq here (and the moving of the
has_cvq assignment).


> +               vi->has_rss_hash_report = true;
> +               vi->rss_indir_table_size = 1;
> +               vi->rss_key_size = VIRTIO_NET_RSS_MAX_KEY_SIZE;
> +       }
> +
> +       if (vi->has_cvq && 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));
> +
> +               dev->hw_features |= NETIF_F_RXHASH;
> +       }
> +
> +       if (vi->has_cvq && 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);
> @@ -3180,9 +3367,6 @@ static int virtnet_probe(struct virtio_device *vdev)
>             virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
>                 vi->any_header_sg = true;
>
> -       if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
> -               vi->has_cvq = true;
> -
>         if (virtio_has_feature(vdev, VIRTIO_NET_F_MTU)) {
>                 mtu = virtio_cread16(vdev,
>                                      offsetof(struct virtio_net_config,
> @@ -3254,6 +3438,12 @@ static int virtnet_probe(struct virtio_device *vdev)
>
>         virtnet_set_queues(vi, vi->curr_queue_pairs);
>
> +       if (vi->has_rss || vi->has_rss_hash_report) {
> +               rtnl_lock();
> +               virtnet_init_default_rss(vi);
> +               rtnl_unlock();
> +       }

I wonder what happens if the user sets a new RSS before this?

Thanks


> +
>         /* Assume link up if device can't report link status,
>            otherwise get link status from config. */
>         netif_carrier_off(dev);
> @@ -3369,7 +3559,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.31.1
>

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

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

* Re: [RFC PATCH 3/3] drivers/net/virtio_net: Added RSS hash report.
  2021-08-18 17:54   ` Andrew Melnychenko
@ 2021-09-01  7:40     ` Jason Wang
  -1 siblings, 0 replies; 19+ messages in thread
From: Jason Wang @ 2021-09-01  7:40 UTC (permalink / raw)
  To: Andrew Melnychenko
  Cc: mst, davem, Jakub Kicinski, virtualization, netdev, linux-kernel

On Thu, Aug 19, 2021 at 1:55 AM Andrew Melnychenko <andrew@daynix.com> wrote:
>
> 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 them 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 | 177 +++++++++++++++++++++++++++++++++++++++
>  1 file changed, 177 insertions(+)
>
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index d87bde246305..6a52eeaf9292 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -1151,6 +1151,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);
> @@ -1177,6 +1179,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;
> @@ -2250,6 +2275,132 @@ static void virtnet_init_default_rss(struct virtnet_info *vi)
>         netdev_rss_key_fill(vi->ctrl->rss.key, vi->rss_key_size);
>  }
>
> +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;
> +       }
> +}
> +
> +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)
>  {
> @@ -2530,8 +2681,28 @@ int virtnet_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, u32 *r
>         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;
>         }
> @@ -2559,6 +2730,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)
> @@ -3351,8 +3523,13 @@ static int virtnet_probe(struct virtio_device *vdev)
>         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;
> +               dev->features |= NETIF_F_NTUPLE;

I think we don't support ntuple filters but hash filters?

Thanks

>         }
>
>         if (vi->has_cvq && vi->has_rss_hash_report)
> --
> 2.31.1
>


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

* Re: [RFC PATCH 3/3] drivers/net/virtio_net: Added RSS hash report.
@ 2021-09-01  7:40     ` Jason Wang
  0 siblings, 0 replies; 19+ messages in thread
From: Jason Wang @ 2021-09-01  7:40 UTC (permalink / raw)
  To: Andrew Melnychenko
  Cc: mst, netdev, linux-kernel, virtualization, Jakub Kicinski, davem

On Thu, Aug 19, 2021 at 1:55 AM Andrew Melnychenko <andrew@daynix.com> wrote:
>
> 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 them 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 | 177 +++++++++++++++++++++++++++++++++++++++
>  1 file changed, 177 insertions(+)
>
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index d87bde246305..6a52eeaf9292 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -1151,6 +1151,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);
> @@ -1177,6 +1179,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;
> @@ -2250,6 +2275,132 @@ static void virtnet_init_default_rss(struct virtnet_info *vi)
>         netdev_rss_key_fill(vi->ctrl->rss.key, vi->rss_key_size);
>  }
>
> +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;
> +       }
> +}
> +
> +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)
>  {
> @@ -2530,8 +2681,28 @@ int virtnet_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, u32 *r
>         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;
>         }
> @@ -2559,6 +2730,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)
> @@ -3351,8 +3523,13 @@ static int virtnet_probe(struct virtio_device *vdev)
>         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;
> +               dev->features |= NETIF_F_NTUPLE;

I think we don't support ntuple filters but hash filters?

Thanks

>         }
>
>         if (vi->has_cvq && vi->has_rss_hash_report)
> --
> 2.31.1
>

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

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

end of thread, other threads:[~2021-09-01  7:40 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-18 17:54 [RFC PATCH 0/3] drivers/net/virtio_net: Added RSS support Andrew Melnychenko
2021-08-18 17:54 ` Andrew Melnychenko
2021-08-18 17:54 ` [RFC PATCH 1/3] drivers/net/virtio_net: Fixed vheader to use v1 Andrew Melnychenko
2021-08-18 17:54   ` Andrew Melnychenko
2021-09-01  6:52   ` Jason Wang
2021-09-01  6:52     ` Jason Wang
2021-08-18 17:54 ` [RFC PATCH 2/3] drivers/net/virtio_net: Added basic RSS support Andrew Melnychenko
2021-08-18 17:54   ` Andrew Melnychenko
2021-08-18 22:38   ` kernel test robot
2021-09-01  7:35   ` Jason Wang
2021-09-01  7:35     ` Jason Wang
2021-08-18 17:54 ` [RFC PATCH 3/3] drivers/net/virtio_net: Added RSS hash report Andrew Melnychenko
2021-08-18 17:54   ` Andrew Melnychenko
2021-08-18 21:33   ` kernel test robot
2021-08-18 21:33   ` [RFC PATCH] drivers/net/virtio_net: virtnet_get_hashflow() can be static kernel test robot
2021-08-19  0:48   ` [RFC PATCH 3/3] drivers/net/virtio_net: Added RSS hash report kernel test robot
2021-09-01  7:40   ` Jason Wang
2021-09-01  7:40     ` Jason Wang
2021-08-31 12:10 ` [RFC PATCH 0/3] drivers/net/virtio_net: Added RSS support Andrew Melnichenko

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.