Replace hardcoded RSS max key size limit with a type based definition.
Add validation for RSS key size against spec minimum (40 bytes). When
validation fails, gracefully disable RSS features and continue
initialization rather than failing completely.

Cc: [email protected]
Fixes: 3f7d9c1964fc ("virtio_net: Add hash_key_length check")
Signed-off-by: Srujana Challa <[email protected]>

v3:
- Moved RSS key validation checks to virtnet_validate.
- Add fixes: tag and CC -stable
---
 drivers/net/virtio_net.c | 29 +++++++++++++++++++++--------
 1 file changed, 21 insertions(+), 8 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index db88dcaefb20..e61cea50dcab 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -381,7 +381,9 @@ struct receive_queue {
        struct xdp_buff **xsk_buffs;
 };
 
-#define VIRTIO_NET_RSS_MAX_KEY_SIZE     40
+#define VIRTIO_NET_RSS_MAX_KEY_SIZE \
+       (type_max(((struct virtio_net_config *)0)->rss_max_key_size) + 1)
+#define VIRTIO_NET_RSS_MIN_KEY_SIZE 40
 
 /* Control VQ buffers: protected by the rtnl lock */
 struct control_buf {
@@ -6627,6 +6629,24 @@ static int virtnet_validate(struct virtio_device *vdev)
                __virtio_clear_bit(vdev, VIRTIO_NET_F_STANDBY);
        }
 
+       if (virtio_has_feature(vdev, VIRTIO_NET_F_RSS) ||
+           virtio_has_feature(vdev, VIRTIO_NET_F_HASH_REPORT)) {
+               u8 key_sz = virtio_cread8(vdev,
+                                         offsetof(struct virtio_net_config,
+                                                  rss_max_key_size));
+               /* Spec requires at least 40 bytes */
+               if (key_sz < VIRTIO_NET_RSS_MIN_KEY_SIZE) {
+                       dev_warn(&vdev->dev,
+                                "rss_max_key_size=%u is less than spec minimum 
%u, disabling RSS\n",
+                                key_sz, VIRTIO_NET_RSS_MIN_KEY_SIZE);
+                       if (virtio_has_feature(vdev, VIRTIO_NET_F_RSS))
+                               __virtio_clear_bit(vdev, VIRTIO_NET_F_RSS);
+                       if (virtio_has_feature(vdev, VIRTIO_NET_F_HASH_REPORT))
+                               __virtio_clear_bit(vdev,
+                                                  VIRTIO_NET_F_HASH_REPORT);
+               }
+       }
+
        return 0;
 }
 
@@ -6839,13 +6859,6 @@ static int virtnet_probe(struct virtio_device *vdev)
        if (vi->has_rss || vi->has_rss_hash_report) {
                vi->rss_key_size =
                        virtio_cread8(vdev, offsetof(struct virtio_net_config, 
rss_max_key_size));
-               if (vi->rss_key_size > VIRTIO_NET_RSS_MAX_KEY_SIZE) {
-                       dev_err(&vdev->dev, "rss_max_key_size=%u exceeds the 
limit %u.\n",
-                               vi->rss_key_size, VIRTIO_NET_RSS_MAX_KEY_SIZE);
-                       err = -EINVAL;
-                       goto free;
-               }
-
                vi->rss_hash_types_supported =
                    virtio_cread32(vdev, offsetof(struct virtio_net_config, 
supported_hash_types));
                vi->rss_hash_types_supported &=
-- 
2.25.1


Reply via email to