drivers/net/virtio_net: Added RSS hash report.
authorAndrew Melnychenko <andrew@daynix.com>
Mon, 28 Mar 2022 17:53:35 +0000 (20:53 +0300)
committerMichael S. Tsirkin <mst@redhat.com>
Mon, 28 Mar 2022 20:52:59 +0000 (16:52 -0400)
Added features for RSS hash report.
If hash is provided - it sets to skb.
Added checks if rss and/or hash are enabled together.

Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
Link: https://lore.kernel.org/r/20220328175336.10802-4-andrew@daynix.com
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
drivers/net/virtio_net.c

index b5f2bb4..c9472c3 100644 (file)
@@ -227,6 +227,7 @@ struct virtnet_info {
 
        /* 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;
@@ -1148,6 +1149,35 @@ xdp_xmit:
        return NULL;
 }
 
+static void virtio_skb_set_hash(const struct virtio_net_hdr_v1_hash *hdr_hash,
+                               struct sk_buff *skb)
+{
+       enum pkt_hash_types rss_hash_type;
+
+       if (!hdr_hash || !skb)
+               return;
+
+       switch ((int)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, (unsigned int)hdr_hash->hash_value, rss_hash_type);
+}
+
 static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
                        void *buf, unsigned int len, void **ctx,
                        unsigned int *xdp_xmit,
@@ -1182,6 +1212,8 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
                return;
 
        hdr = skb_vnet_hdr(skb);
+       if (dev->features & NETIF_F_RXHASH && vi->has_rss_hash_report)
+               virtio_skb_set_hash((const struct virtio_net_hdr_v1_hash *)hdr, skb);
 
        if (hdr->hdr.flags & VIRTIO_NET_HDR_F_DATA_VALID)
                skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -2232,7 +2264,8 @@ static bool virtnet_commit_rss_command(struct virtnet_info *vi)
        sg_set_buf(&sgs[3], vi->ctrl->rss.key, sg_buf_size);
 
        if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MQ,
-                                 VIRTIO_NET_CTRL_MQ_RSS_CONFIG, sgs)) {
+                                 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;
        }
@@ -3231,6 +3264,8 @@ static bool virtnet_validate_features(struct virtio_device *vdev)
             VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR,
                             "VIRTIO_NET_F_CTRL_VQ") ||
             VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_RSS,
+                            "VIRTIO_NET_F_CTRL_VQ") ||
+            VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_HASH_REPORT,
                             "VIRTIO_NET_F_CTRL_VQ"))) {
                return false;
        }
@@ -3366,8 +3401,13 @@ 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_RSS)) {
+       if (virtio_has_feature(vdev, VIRTIO_NET_F_HASH_REPORT))
+               vi->has_rss_hash_report = true;
+
+       if (virtio_has_feature(vdev, VIRTIO_NET_F_RSS))
                vi->has_rss = true;
+
+       if (vi->has_rss || vi->has_rss_hash_report) {
                vi->rss_indir_table_size =
                        virtio_cread16(vdev, offsetof(struct virtio_net_config,
                                rss_max_indirection_table_length));
@@ -3383,8 +3423,11 @@ static int virtnet_probe(struct virtio_device *vdev)
 
                dev->hw_features |= NETIF_F_RXHASH;
        }
-       if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF) ||
-           virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
+
+       if (vi->has_rss_hash_report)
+               vi->hdr_len = sizeof(struct virtio_net_hdr_v1_hash);
+       else if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF) ||
+                virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
                vi->hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
        else
                vi->hdr_len = sizeof(struct virtio_net_hdr);
@@ -3451,7 +3494,7 @@ static int virtnet_probe(struct virtio_device *vdev)
                }
        }
 
-       if (vi->has_rss)
+       if (vi->has_rss || vi->has_rss_hash_report)
                virtnet_init_default_rss(vi);
 
        err = register_netdev(dev);
@@ -3586,7 +3629,7 @@ static struct virtio_device_id id_table[] = {
        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_RSS
+       VIRTIO_NET_F_RSS, VIRTIO_NET_F_HASH_REPORT
 
 static unsigned int features[] = {
        VIRTNET_FEATURES,