* [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.