[PATCH RFC v2 08/13] qmp: update virtio features map to support extended features

Paolo Abeni posted 13 patches 5 months ago
Maintainers: Dmitry Fleytman <dmitry.fleytman@gmail.com>, Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>, Jason Wang <jasowang@redhat.com>, Sriram Yagnaraman <sriram.yagnaraman@ericsson.com>, "Michael S. Tsirkin" <mst@redhat.com>, Stefano Garzarella <sgarzare@redhat.com>, Cornelia Huck <cohuck@redhat.com>, Paolo Bonzini <pbonzini@redhat.com>, Luigi Rizzo <rizzo@iet.unipi.it>, Giuseppe Lettieri <g.lettieri@iet.unipi.it>, Vincenzo Maffione <v.maffione@gmail.com>, Eric Blake <eblake@redhat.com>, Markus Armbruster <armbru@redhat.com>
There is a newer version of this series
[PATCH RFC v2 08/13] qmp: update virtio features map to support extended features
Posted by Paolo Abeni 5 months ago
Extend the VirtioDeviceFeatures struct with an additional u64
to track unknown features in the 65-128 bit range and decode
the full virtio features spaces for vhost and virtio devices.

Signed-off-by: Paolo Abeni <pabeni@redhat.com>
---
I'm unsure if it's actually legit to update a qapi struct
definition?

v1 -> v2:
  - uint128_t -> uint64_t[]
---
 hw/virtio/virtio-hmp-cmds.c |  3 +-
 hw/virtio/virtio-qmp.c      | 89 ++++++++++++++++++++++++++-----------
 hw/virtio/virtio-qmp.h      |  3 +-
 qapi/virtio.json            |  8 +++-
 4 files changed, 73 insertions(+), 30 deletions(-)

diff --git a/hw/virtio/virtio-hmp-cmds.c b/hw/virtio/virtio-hmp-cmds.c
index 7d8677bcf0..e8c2a76a2a 100644
--- a/hw/virtio/virtio-hmp-cmds.c
+++ b/hw/virtio/virtio-hmp-cmds.c
@@ -74,7 +74,8 @@ static void hmp_virtio_dump_features(Monitor *mon,
     }
 
     if (features->has_unknown_dev_features) {
-        monitor_printf(mon, "  unknown-features(0x%016"PRIx64")\n",
+        monitor_printf(mon, "  unknown-features(0x%016"PRIx64"%016"PRIx64")\n",
+                       features->unknown_dev_features_dword2,
                        features->unknown_dev_features);
     }
 }
diff --git a/hw/virtio/virtio-qmp.c b/hw/virtio/virtio-qmp.c
index 3b6377cf0d..0d06e7a7db 100644
--- a/hw/virtio/virtio-qmp.c
+++ b/hw/virtio/virtio-qmp.c
@@ -325,6 +325,20 @@ static const qmp_virtio_feature_map_t virtio_net_feature_map[] = {
     FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \
             "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features "
             "negotiation supported"),
+    FEATURE_ENTRY(VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO, \
+            "VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO: Driver can receive GSO over "
+            "UDP tunnel packets"),
+    FEATURE_ENTRY(VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO_CSUM, \
+            "VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO: Driver can receive GSO over "
+            "UDP tunnel packets requiring checksum offload for the outer "
+            "header"),
+    FEATURE_ENTRY(VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO, \
+            "VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO: Device can receive GSO over "
+            "UDP tunnel packets"),
+    FEATURE_ENTRY(VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO_CSUM, \
+            "VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO: Device can receive GSO over "
+            "UDP tunnel packets requiring checksum offload for the outer "
+            "header"),
     { -1, "" }
 };
 #endif
@@ -510,6 +524,24 @@ static const qmp_virtio_feature_map_t virtio_gpio_feature_map[] = {
         list;                                            \
     })
 
+#define CONVERT_FEATURES_EX(type, map, bitmap)           \
+    ({                                                   \
+        type *list = NULL;                               \
+        type *node;                                      \
+        for (i = 0; map[i].virtio_bit != -1; i++) {      \
+            bit = map[i].virtio_bit;                     \
+            if (!virtio_has_feature_ex(bitmap, bit)) {   \
+                continue;                                \
+            }                                            \
+            node = g_new0(type, 1);                      \
+            node->value = g_strdup(map[i].feature_desc); \
+            node->next = list;                           \
+            list = node;                                 \
+            virtio_clear_feature_ex(bitmap, bit);        \
+        }                                                \
+        list;                                            \
+    })
+
 VirtioDeviceStatus *qmp_decode_status(uint8_t bitmap)
 {
     VirtioDeviceStatus *status;
@@ -545,109 +577,112 @@ VhostDeviceProtocols *qmp_decode_protocols(uint64_t bitmap)
     return vhu_protocols;
 }
 
-VirtioDeviceFeatures *qmp_decode_features(uint16_t device_id, uint64_t bitmap)
+VirtioDeviceFeatures *qmp_decode_features(uint16_t device_id,
+                                          const uint64_t *bmap)
 {
+    uint64_t bitmap[VIRTIO_FEATURES_DWORDS];
     VirtioDeviceFeatures *features;
     uint64_t bit;
     int i;
 
+    virtio_features_copy(bitmap, bmap);
     features = g_new0(VirtioDeviceFeatures, 1);
     features->has_dev_features = true;
 
     /* transport features */
-    features->transports = CONVERT_FEATURES(strList, virtio_transport_map, 0,
-                                            bitmap);
+    features->transports = CONVERT_FEATURES_EX(strList, virtio_transport_map,
+                                               bitmap);
 
     /* device features */
     switch (device_id) {
 #ifdef CONFIG_VIRTIO_SERIAL
     case VIRTIO_ID_CONSOLE:
         features->dev_features =
-            CONVERT_FEATURES(strList, virtio_serial_feature_map, 0, bitmap);
+            CONVERT_FEATURES_EX(strList, virtio_serial_feature_map, bitmap);
         break;
 #endif
 #ifdef CONFIG_VIRTIO_BLK
     case VIRTIO_ID_BLOCK:
         features->dev_features =
-            CONVERT_FEATURES(strList, virtio_blk_feature_map, 0, bitmap);
+            CONVERT_FEATURES_EX(strList, virtio_blk_feature_map, bitmap);
         break;
 #endif
 #ifdef CONFIG_VIRTIO_GPU
     case VIRTIO_ID_GPU:
         features->dev_features =
-            CONVERT_FEATURES(strList, virtio_gpu_feature_map, 0, bitmap);
+            CONVERT_FEATURES_EX(strList, virtio_gpu_feature_map, bitmap);
         break;
 #endif
 #ifdef CONFIG_VIRTIO_NET
     case VIRTIO_ID_NET:
         features->dev_features =
-            CONVERT_FEATURES(strList, virtio_net_feature_map, 0, bitmap);
+            CONVERT_FEATURES_EX(strList, virtio_net_feature_map, bitmap);
         break;
 #endif
 #ifdef CONFIG_VIRTIO_SCSI
     case VIRTIO_ID_SCSI:
         features->dev_features =
-            CONVERT_FEATURES(strList, virtio_scsi_feature_map, 0, bitmap);
+            CONVERT_FEATURES_EX(strList, virtio_scsi_feature_map, bitmap);
         break;
 #endif
 #ifdef CONFIG_VIRTIO_BALLOON
     case VIRTIO_ID_BALLOON:
         features->dev_features =
-            CONVERT_FEATURES(strList, virtio_balloon_feature_map, 0, bitmap);
+            CONVERT_FEATURES_EX(strList, virtio_balloon_feature_map, bitmap);
         break;
 #endif
 #ifdef CONFIG_VIRTIO_IOMMU
     case VIRTIO_ID_IOMMU:
         features->dev_features =
-            CONVERT_FEATURES(strList, virtio_iommu_feature_map, 0, bitmap);
+            CONVERT_FEATURES_EX(strList, virtio_iommu_feature_map, bitmap);
         break;
 #endif
 #ifdef CONFIG_VIRTIO_INPUT
     case VIRTIO_ID_INPUT:
         features->dev_features =
-            CONVERT_FEATURES(strList, virtio_input_feature_map, 0, bitmap);
+            CONVERT_FEATURES_EX(strList, virtio_input_feature_map, bitmap);
         break;
 #endif
 #ifdef CONFIG_VHOST_USER_FS
     case VIRTIO_ID_FS:
         features->dev_features =
-            CONVERT_FEATURES(strList, virtio_fs_feature_map, 0, bitmap);
+            CONVERT_FEATURES_EX(strList, virtio_fs_feature_map, bitmap);
         break;
 #endif
 #ifdef CONFIG_VHOST_VSOCK
     case VIRTIO_ID_VSOCK:
         features->dev_features =
-            CONVERT_FEATURES(strList, virtio_vsock_feature_map, 0, bitmap);
+            CONVERT_FEATURES_EX(strList, virtio_vsock_feature_map, bitmap);
         break;
 #endif
 #ifdef CONFIG_VIRTIO_CRYPTO
     case VIRTIO_ID_CRYPTO:
         features->dev_features =
-            CONVERT_FEATURES(strList, virtio_crypto_feature_map, 0, bitmap);
+            CONVERT_FEATURES_EX(strList, virtio_crypto_feature_map, bitmap);
         break;
 #endif
 #ifdef CONFIG_VIRTIO_MEM
     case VIRTIO_ID_MEM:
         features->dev_features =
-            CONVERT_FEATURES(strList, virtio_mem_feature_map, 0, bitmap);
+            CONVERT_FEATURES_EX(strList, virtio_mem_feature_map, bitmap);
         break;
 #endif
 #ifdef CONFIG_VIRTIO_I2C_ADAPTER
     case VIRTIO_ID_I2C_ADAPTER:
         features->dev_features =
-            CONVERT_FEATURES(strList, virtio_i2c_feature_map, 0, bitmap);
+            CONVERT_FEATURES_EX(strList, virtio_i2c_feature_map, bitmap);
         break;
 #endif
 #ifdef CONFIG_VIRTIO_RNG
     case VIRTIO_ID_RNG:
         features->dev_features =
-            CONVERT_FEATURES(strList, virtio_rng_feature_map, 0, bitmap);
+            CONVERT_FEATURES_EX(strList, virtio_rng_feature_map, bitmap);
         break;
 #endif
 #ifdef CONFIG_VHOST_USER_GPIO
     case VIRTIO_ID_GPIO:
         features->dev_features =
-            CONVERT_FEATURES(strList, virtio_gpio_feature_map, 0, bitmap);
+            CONVERT_FEATURES_EX(strList, virtio_gpio_feature_map, bitmap);
         break;
 #endif
     /* No features */
@@ -680,9 +715,10 @@ VirtioDeviceFeatures *qmp_decode_features(uint16_t device_id, uint64_t bitmap)
         g_assert_not_reached();
     }
 
-    features->has_unknown_dev_features = bitmap != 0;
+    features->has_unknown_dev_features = virtio_features_is_empty(bitmap);
     if (features->has_unknown_dev_features) {
-        features->unknown_dev_features = bitmap;
+        features->unknown_dev_features = bitmap[0];
+        features->unknown_dev_features_dword2 = bitmap[1];
     }
 
     return features;
@@ -743,11 +779,11 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
     status->device_id = vdev->device_id;
     status->vhost_started = vdev->vhost_started;
     status->guest_features = qmp_decode_features(vdev->device_id,
-                                                 vdev->guest_features);
+                                                 vdev->guest_features_array);
     status->host_features = qmp_decode_features(vdev->device_id,
-                                                vdev->host_features);
+                                                vdev->host_features_array);
     status->backend_features = qmp_decode_features(vdev->device_id,
-                                                   vdev->backend_features);
+                                                 vdev->backend_features_array);
 
     switch (vdev->device_endian) {
     case VIRTIO_DEVICE_ENDIAN_LITTLE:
@@ -785,11 +821,12 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
         status->vhost_dev->nvqs = hdev->nvqs;
         status->vhost_dev->vq_index = hdev->vq_index;
         status->vhost_dev->features =
-            qmp_decode_features(vdev->device_id, hdev->features);
+            qmp_decode_features(vdev->device_id, hdev->features_array);
         status->vhost_dev->acked_features =
-            qmp_decode_features(vdev->device_id, hdev->acked_features);
+            qmp_decode_features(vdev->device_id, hdev->acked_features_array);
         status->vhost_dev->backend_features =
-            qmp_decode_features(vdev->device_id, hdev->backend_features);
+            qmp_decode_features(vdev->device_id, hdev->backend_features_array);
+
         status->vhost_dev->protocol_features =
             qmp_decode_protocols(hdev->protocol_features);
         status->vhost_dev->max_queues = hdev->max_queues;
diff --git a/hw/virtio/virtio-qmp.h b/hw/virtio/virtio-qmp.h
index 245a446a56..e0a1e49035 100644
--- a/hw/virtio/virtio-qmp.h
+++ b/hw/virtio/virtio-qmp.h
@@ -18,6 +18,7 @@
 VirtIODevice *qmp_find_virtio_device(const char *path);
 VirtioDeviceStatus *qmp_decode_status(uint8_t bitmap);
 VhostDeviceProtocols *qmp_decode_protocols(uint64_t bitmap);
-VirtioDeviceFeatures *qmp_decode_features(uint16_t device_id, uint64_t bitmap);
+VirtioDeviceFeatures *qmp_decode_features(uint16_t device_id,
+                                          const uint64_t *bitmap);
 
 #endif
diff --git a/qapi/virtio.json b/qapi/virtio.json
index 73df718a26..f0442e144b 100644
--- a/qapi/virtio.json
+++ b/qapi/virtio.json
@@ -488,14 +488,18 @@
 #     unique features)
 #
 # @unknown-dev-features: Virtio device features bitmap that have not
-#     been decoded
+#     been decoded (lower 64 bit)
+#
+# @unknown-dev-features-dword2: Virtio device features bitmap that have not
+#     been decoded (bits 65-128)
 #
 # Since: 7.2
 ##
 { 'struct': 'VirtioDeviceFeatures',
   'data': { 'transports': [ 'str' ],
             '*dev-features': [ 'str' ],
-            '*unknown-dev-features': 'uint64' } }
+            '*unknown-dev-features': 'uint64',
+            '*unknown-dev-features-dword2': 'uint64' } }
 
 ##
 # @VirtQueueStatus:
-- 
2.50.0
Re: [PATCH RFC v2 08/13] qmp: update virtio features map to support extended features
Posted by Akihiko Odaki 5 months ago
On 2025/07/11 22:02, Paolo Abeni wrote:
> Extend the VirtioDeviceFeatures struct with an additional u64
> to track unknown features in the 65-128 bit range and decode
> the full virtio features spaces for vhost and virtio devices.
> 
> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
> ---
> I'm unsure if it's actually legit to update a qapi struct
> definition?
> 
> v1 -> v2:
>    - uint128_t -> uint64_t[]
> ---
>   hw/virtio/virtio-hmp-cmds.c |  3 +-
>   hw/virtio/virtio-qmp.c      | 89 ++++++++++++++++++++++++++-----------
>   hw/virtio/virtio-qmp.h      |  3 +-
>   qapi/virtio.json            |  8 +++-
>   4 files changed, 73 insertions(+), 30 deletions(-)
> 
> diff --git a/hw/virtio/virtio-hmp-cmds.c b/hw/virtio/virtio-hmp-cmds.c
> index 7d8677bcf0..e8c2a76a2a 100644
> --- a/hw/virtio/virtio-hmp-cmds.c
> +++ b/hw/virtio/virtio-hmp-cmds.c
> @@ -74,7 +74,8 @@ static void hmp_virtio_dump_features(Monitor *mon,
>       }
>   
>       if (features->has_unknown_dev_features) {
> -        monitor_printf(mon, "  unknown-features(0x%016"PRIx64")\n",
> +        monitor_printf(mon, "  unknown-features(0x%016"PRIx64"%016"PRIx64")\n",
> +                       features->unknown_dev_features_dword2,
>                          features->unknown_dev_features);
>       }
>   }
> diff --git a/hw/virtio/virtio-qmp.c b/hw/virtio/virtio-qmp.c
> index 3b6377cf0d..0d06e7a7db 100644
> --- a/hw/virtio/virtio-qmp.c
> +++ b/hw/virtio/virtio-qmp.c
> @@ -325,6 +325,20 @@ static const qmp_virtio_feature_map_t virtio_net_feature_map[] = {
>       FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \
>               "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features "
>               "negotiation supported"),
> +    FEATURE_ENTRY(VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO, \
> +            "VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO: Driver can receive GSO over "
> +            "UDP tunnel packets"),
> +    FEATURE_ENTRY(VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO_CSUM, \
> +            "VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO: Driver can receive GSO over "
> +            "UDP tunnel packets requiring checksum offload for the outer "
> +            "header"),
> +    FEATURE_ENTRY(VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO, \
> +            "VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO: Device can receive GSO over "
> +            "UDP tunnel packets"),
> +    FEATURE_ENTRY(VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO_CSUM, \
> +            "VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO: Device can receive GSO over "
> +            "UDP tunnel packets requiring checksum offload for the outer "
> +            "header"),
>       { -1, "" }
>   };
>   #endif
> @@ -510,6 +524,24 @@ static const qmp_virtio_feature_map_t virtio_gpio_feature_map[] = {
>           list;                                            \
>       })
>   
> +#define CONVERT_FEATURES_EX(type, map, bitmap)           \
> +    ({                                                   \
> +        type *list = NULL;                               \
> +        type *node;                                      \
> +        for (i = 0; map[i].virtio_bit != -1; i++) {      \
> +            bit = map[i].virtio_bit;                     \
> +            if (!virtio_has_feature_ex(bitmap, bit)) {   \
> +                continue;                                \
> +            }                                            \
> +            node = g_new0(type, 1);                      \
> +            node->value = g_strdup(map[i].feature_desc); \
> +            node->next = list;                           \
> +            list = node;                                 \
> +            virtio_clear_feature_ex(bitmap, bit);        \
> +        }                                                \
> +        list;                                            \
> +    })
> +
>   VirtioDeviceStatus *qmp_decode_status(uint8_t bitmap)
>   {
>       VirtioDeviceStatus *status;
> @@ -545,109 +577,112 @@ VhostDeviceProtocols *qmp_decode_protocols(uint64_t bitmap)
>       return vhu_protocols;
>   }
>   
> -VirtioDeviceFeatures *qmp_decode_features(uint16_t device_id, uint64_t bitmap)
> +VirtioDeviceFeatures *qmp_decode_features(uint16_t device_id,
> +                                          const uint64_t *bmap)
>   {
> +    uint64_t bitmap[VIRTIO_FEATURES_DWORDS];
>       VirtioDeviceFeatures *features;
>       uint64_t bit;
>       int i;
>   
> +    virtio_features_copy(bitmap, bmap);
>       features = g_new0(VirtioDeviceFeatures, 1);
>       features->has_dev_features = true;
>   
>       /* transport features */
> -    features->transports = CONVERT_FEATURES(strList, virtio_transport_map, 0,
> -                                            bitmap);
> +    features->transports = CONVERT_FEATURES_EX(strList, virtio_transport_map,
> +                                               bitmap);
>   
>       /* device features */
>       switch (device_id) {
>   #ifdef CONFIG_VIRTIO_SERIAL
>       case VIRTIO_ID_CONSOLE:
>           features->dev_features =
> -            CONVERT_FEATURES(strList, virtio_serial_feature_map, 0, bitmap);
> +            CONVERT_FEATURES_EX(strList, virtio_serial_feature_map, bitmap);
>           break;
>   #endif
>   #ifdef CONFIG_VIRTIO_BLK
>       case VIRTIO_ID_BLOCK:
>           features->dev_features =
> -            CONVERT_FEATURES(strList, virtio_blk_feature_map, 0, bitmap);
> +            CONVERT_FEATURES_EX(strList, virtio_blk_feature_map, bitmap);
>           break;
>   #endif
>   #ifdef CONFIG_VIRTIO_GPU
>       case VIRTIO_ID_GPU:
>           features->dev_features =
> -            CONVERT_FEATURES(strList, virtio_gpu_feature_map, 0, bitmap);
> +            CONVERT_FEATURES_EX(strList, virtio_gpu_feature_map, bitmap);
>           break;
>   #endif
>   #ifdef CONFIG_VIRTIO_NET
>       case VIRTIO_ID_NET:
>           features->dev_features =
> -            CONVERT_FEATURES(strList, virtio_net_feature_map, 0, bitmap);
> +            CONVERT_FEATURES_EX(strList, virtio_net_feature_map, bitmap);
>           break;
>   #endif
>   #ifdef CONFIG_VIRTIO_SCSI
>       case VIRTIO_ID_SCSI:
>           features->dev_features =
> -            CONVERT_FEATURES(strList, virtio_scsi_feature_map, 0, bitmap);
> +            CONVERT_FEATURES_EX(strList, virtio_scsi_feature_map, bitmap);
>           break;
>   #endif
>   #ifdef CONFIG_VIRTIO_BALLOON
>       case VIRTIO_ID_BALLOON:
>           features->dev_features =
> -            CONVERT_FEATURES(strList, virtio_balloon_feature_map, 0, bitmap);
> +            CONVERT_FEATURES_EX(strList, virtio_balloon_feature_map, bitmap);
>           break;
>   #endif
>   #ifdef CONFIG_VIRTIO_IOMMU
>       case VIRTIO_ID_IOMMU:
>           features->dev_features =
> -            CONVERT_FEATURES(strList, virtio_iommu_feature_map, 0, bitmap);
> +            CONVERT_FEATURES_EX(strList, virtio_iommu_feature_map, bitmap);
>           break;
>   #endif
>   #ifdef CONFIG_VIRTIO_INPUT
>       case VIRTIO_ID_INPUT:
>           features->dev_features =
> -            CONVERT_FEATURES(strList, virtio_input_feature_map, 0, bitmap);
> +            CONVERT_FEATURES_EX(strList, virtio_input_feature_map, bitmap);
>           break;
>   #endif
>   #ifdef CONFIG_VHOST_USER_FS
>       case VIRTIO_ID_FS:
>           features->dev_features =
> -            CONVERT_FEATURES(strList, virtio_fs_feature_map, 0, bitmap);
> +            CONVERT_FEATURES_EX(strList, virtio_fs_feature_map, bitmap);
>           break;
>   #endif
>   #ifdef CONFIG_VHOST_VSOCK
>       case VIRTIO_ID_VSOCK:
>           features->dev_features =
> -            CONVERT_FEATURES(strList, virtio_vsock_feature_map, 0, bitmap);
> +            CONVERT_FEATURES_EX(strList, virtio_vsock_feature_map, bitmap);
>           break;
>   #endif
>   #ifdef CONFIG_VIRTIO_CRYPTO
>       case VIRTIO_ID_CRYPTO:
>           features->dev_features =
> -            CONVERT_FEATURES(strList, virtio_crypto_feature_map, 0, bitmap);
> +            CONVERT_FEATURES_EX(strList, virtio_crypto_feature_map, bitmap);
>           break;
>   #endif
>   #ifdef CONFIG_VIRTIO_MEM
>       case VIRTIO_ID_MEM:
>           features->dev_features =
> -            CONVERT_FEATURES(strList, virtio_mem_feature_map, 0, bitmap);
> +            CONVERT_FEATURES_EX(strList, virtio_mem_feature_map, bitmap);
>           break;
>   #endif
>   #ifdef CONFIG_VIRTIO_I2C_ADAPTER
>       case VIRTIO_ID_I2C_ADAPTER:
>           features->dev_features =
> -            CONVERT_FEATURES(strList, virtio_i2c_feature_map, 0, bitmap);
> +            CONVERT_FEATURES_EX(strList, virtio_i2c_feature_map, bitmap);
>           break;
>   #endif
>   #ifdef CONFIG_VIRTIO_RNG
>       case VIRTIO_ID_RNG:
>           features->dev_features =
> -            CONVERT_FEATURES(strList, virtio_rng_feature_map, 0, bitmap);
> +            CONVERT_FEATURES_EX(strList, virtio_rng_feature_map, bitmap);
>           break;
>   #endif
>   #ifdef CONFIG_VHOST_USER_GPIO
>       case VIRTIO_ID_GPIO:
>           features->dev_features =
> -            CONVERT_FEATURES(strList, virtio_gpio_feature_map, 0, bitmap);
> +            CONVERT_FEATURES_EX(strList, virtio_gpio_feature_map, bitmap);
>           break;
>   #endif
>       /* No features */
> @@ -680,9 +715,10 @@ VirtioDeviceFeatures *qmp_decode_features(uint16_t device_id, uint64_t bitmap)
>           g_assert_not_reached();
>       }
>   
> -    features->has_unknown_dev_features = bitmap != 0;
> +    features->has_unknown_dev_features = virtio_features_is_empty(bitmap);
>       if (features->has_unknown_dev_features) {
> -        features->unknown_dev_features = bitmap;
> +        features->unknown_dev_features = bitmap[0];
> +        features->unknown_dev_features_dword2 = bitmap[1];
>       }
>   
>       return features;
> @@ -743,11 +779,11 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
>       status->device_id = vdev->device_id;
>       status->vhost_started = vdev->vhost_started;
>       status->guest_features = qmp_decode_features(vdev->device_id,
> -                                                 vdev->guest_features);
> +                                                 vdev->guest_features_array);
>       status->host_features = qmp_decode_features(vdev->device_id,
> -                                                vdev->host_features);
> +                                                vdev->host_features_array);
>       status->backend_features = qmp_decode_features(vdev->device_id,
> -                                                   vdev->backend_features);
> +                                                 vdev->backend_features_array);
>   
>       switch (vdev->device_endian) {
>       case VIRTIO_DEVICE_ENDIAN_LITTLE:
> @@ -785,11 +821,12 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
>           status->vhost_dev->nvqs = hdev->nvqs;
>           status->vhost_dev->vq_index = hdev->vq_index;
>           status->vhost_dev->features =
> -            qmp_decode_features(vdev->device_id, hdev->features);
> +            qmp_decode_features(vdev->device_id, hdev->features_array);
>           status->vhost_dev->acked_features =
> -            qmp_decode_features(vdev->device_id, hdev->acked_features);
> +            qmp_decode_features(vdev->device_id, hdev->acked_features_array);
>           status->vhost_dev->backend_features =
> -            qmp_decode_features(vdev->device_id, hdev->backend_features);
> +            qmp_decode_features(vdev->device_id, hdev->backend_features_array);
> +
>           status->vhost_dev->protocol_features =
>               qmp_decode_protocols(hdev->protocol_features);
>           status->vhost_dev->max_queues = hdev->max_queues;
> diff --git a/hw/virtio/virtio-qmp.h b/hw/virtio/virtio-qmp.h
> index 245a446a56..e0a1e49035 100644
> --- a/hw/virtio/virtio-qmp.h
> +++ b/hw/virtio/virtio-qmp.h
> @@ -18,6 +18,7 @@
>   VirtIODevice *qmp_find_virtio_device(const char *path);
>   VirtioDeviceStatus *qmp_decode_status(uint8_t bitmap);
>   VhostDeviceProtocols *qmp_decode_protocols(uint64_t bitmap);
> -VirtioDeviceFeatures *qmp_decode_features(uint16_t device_id, uint64_t bitmap);
> +VirtioDeviceFeatures *qmp_decode_features(uint16_t device_id,
> +                                          const uint64_t *bitmap);
>   
>   #endif
> diff --git a/qapi/virtio.json b/qapi/virtio.json
> index 73df718a26..f0442e144b 100644
> --- a/qapi/virtio.json
> +++ b/qapi/virtio.json
> @@ -488,14 +488,18 @@
>   #     unique features)
>   #
>   # @unknown-dev-features: Virtio device features bitmap that have not
> -#     been decoded
> +#     been decoded (lower 64 bit)
> +#
> +# @unknown-dev-features-dword2: Virtio device features bitmap that have not
> +#     been decoded (bits 65-128)
>   #
>   # Since: 7.2
>   ##
>   { 'struct': 'VirtioDeviceFeatures',
>     'data': { 'transports': [ 'str' ],
>               '*dev-features': [ 'str' ],
> -            '*unknown-dev-features': 'uint64' } }
> +            '*unknown-dev-features': 'uint64',
> +            '*unknown-dev-features-dword2': 'uint64' } }

Let's omit "dword" for consistency with unknown-dev-features, which is 
also uint64 but don't have the keyword.

By the way, "dword" is somewhat confusing in QEMU; in many cases (if not 
all), it represents 32-bit because of Windows and PCI, which define 
dword as 32-bit. "U64" is a more common phrase.

>   
>   ##
>   # @VirtQueueStatus:
Re: [PATCH RFC v2 08/13] qmp: update virtio features map to support extended features
Posted by Paolo Abeni 5 months ago
On 7/15/25 9:59 AM, Akihiko Odaki wrote:
> On 2025/07/11 22:02, Paolo Abeni wrote:
>> @@ -785,11 +821,12 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
>>           status->vhost_dev->nvqs = hdev->nvqs;
>>           status->vhost_dev->vq_index = hdev->vq_index;
>>           status->vhost_dev->features =
>> -            qmp_decode_features(vdev->device_id, hdev->features);
>> +            qmp_decode_features(vdev->device_id, hdev->features_array);
>>           status->vhost_dev->acked_features =
>> -            qmp_decode_features(vdev->device_id, hdev->acked_features);
>> +            qmp_decode_features(vdev->device_id, hdev->acked_features_array);
>>           status->vhost_dev->backend_features =
>> -            qmp_decode_features(vdev->device_id, hdev->backend_features);
>> +            qmp_decode_features(vdev->device_id, hdev->backend_features_array);
>> +
>>           status->vhost_dev->protocol_features =
>>               qmp_decode_protocols(hdev->protocol_features);
>>           status->vhost_dev->max_queues = hdev->max_queues;
>> diff --git a/hw/virtio/virtio-qmp.h b/hw/virtio/virtio-qmp.h
>> index 245a446a56..e0a1e49035 100644
>> --- a/hw/virtio/virtio-qmp.h
>> +++ b/hw/virtio/virtio-qmp.h
>> @@ -18,6 +18,7 @@
>>   VirtIODevice *qmp_find_virtio_device(const char *path);
>>   VirtioDeviceStatus *qmp_decode_status(uint8_t bitmap);
>>   VhostDeviceProtocols *qmp_decode_protocols(uint64_t bitmap);
>> -VirtioDeviceFeatures *qmp_decode_features(uint16_t device_id, uint64_t bitmap);
>> +VirtioDeviceFeatures *qmp_decode_features(uint16_t device_id,
>> +                                          const uint64_t *bitmap);
>>   
>>   #endif
>> diff --git a/qapi/virtio.json b/qapi/virtio.json
>> index 73df718a26..f0442e144b 100644
>> --- a/qapi/virtio.json
>> +++ b/qapi/virtio.json
>> @@ -488,14 +488,18 @@
>>   #     unique features)
>>   #
>>   # @unknown-dev-features: Virtio device features bitmap that have not
>> -#     been decoded
>> +#     been decoded (lower 64 bit)
>> +#
>> +# @unknown-dev-features-dword2: Virtio device features bitmap that have not
>> +#     been decoded (bits 65-128)
>>   #
>>   # Since: 7.2
>>   ##
>>   { 'struct': 'VirtioDeviceFeatures',
>>     'data': { 'transports': [ 'str' ],
>>               '*dev-features': [ 'str' ],
>> -            '*unknown-dev-features': 'uint64' } }
>> +            '*unknown-dev-features': 'uint64',
>> +            '*unknown-dev-features-dword2': 'uint64' } }
> 
> Let's omit "dword" for consistency with unknown-dev-features, which is 
> also uint64 but don't have the keyword.

Ok. Can I infer that is actually legit to update a qapi struct
definition? It's not clear to me it such change violates any qemu
assumptions.

/P
Re: [PATCH RFC v2 08/13] qmp: update virtio features map to support extended features
Posted by Akihiko Odaki 5 months ago
On 2025/07/16 0:43, Paolo Abeni wrote:
> On 7/15/25 9:59 AM, Akihiko Odaki wrote:
>> On 2025/07/11 22:02, Paolo Abeni wrote:
>>> @@ -785,11 +821,12 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
>>>            status->vhost_dev->nvqs = hdev->nvqs;
>>>            status->vhost_dev->vq_index = hdev->vq_index;
>>>            status->vhost_dev->features =
>>> -            qmp_decode_features(vdev->device_id, hdev->features);
>>> +            qmp_decode_features(vdev->device_id, hdev->features_array);
>>>            status->vhost_dev->acked_features =
>>> -            qmp_decode_features(vdev->device_id, hdev->acked_features);
>>> +            qmp_decode_features(vdev->device_id, hdev->acked_features_array);
>>>            status->vhost_dev->backend_features =
>>> -            qmp_decode_features(vdev->device_id, hdev->backend_features);
>>> +            qmp_decode_features(vdev->device_id, hdev->backend_features_array);
>>> +
>>>            status->vhost_dev->protocol_features =
>>>                qmp_decode_protocols(hdev->protocol_features);
>>>            status->vhost_dev->max_queues = hdev->max_queues;
>>> diff --git a/hw/virtio/virtio-qmp.h b/hw/virtio/virtio-qmp.h
>>> index 245a446a56..e0a1e49035 100644
>>> --- a/hw/virtio/virtio-qmp.h
>>> +++ b/hw/virtio/virtio-qmp.h
>>> @@ -18,6 +18,7 @@
>>>    VirtIODevice *qmp_find_virtio_device(const char *path);
>>>    VirtioDeviceStatus *qmp_decode_status(uint8_t bitmap);
>>>    VhostDeviceProtocols *qmp_decode_protocols(uint64_t bitmap);
>>> -VirtioDeviceFeatures *qmp_decode_features(uint16_t device_id, uint64_t bitmap);
>>> +VirtioDeviceFeatures *qmp_decode_features(uint16_t device_id,
>>> +                                          const uint64_t *bitmap);
>>>    
>>>    #endif
>>> diff --git a/qapi/virtio.json b/qapi/virtio.json
>>> index 73df718a26..f0442e144b 100644
>>> --- a/qapi/virtio.json
>>> +++ b/qapi/virtio.json
>>> @@ -488,14 +488,18 @@
>>>    #     unique features)
>>>    #
>>>    # @unknown-dev-features: Virtio device features bitmap that have not
>>> -#     been decoded
>>> +#     been decoded (lower 64 bit)
>>> +#
>>> +# @unknown-dev-features-dword2: Virtio device features bitmap that have not
>>> +#     been decoded (bits 65-128)
>>>    #
>>>    # Since: 7.2
>>>    ##
>>>    { 'struct': 'VirtioDeviceFeatures',
>>>      'data': { 'transports': [ 'str' ],
>>>                '*dev-features': [ 'str' ],
>>> -            '*unknown-dev-features': 'uint64' } }
>>> +            '*unknown-dev-features': 'uint64',
>>> +            '*unknown-dev-features-dword2': 'uint64' } }
>>
>> Let's omit "dword" for consistency with unknown-dev-features, which is
>> also uint64 but don't have the keyword.
> 
> Ok. Can I infer that is actually legit to update a qapi struct
> definition? It's not clear to me it such change violates any qemu
> assumptions.

Adding a property is fine but renaming one is not as it can break 
application that use QAPI such as libvirt. For some guidance, please 
see: docs/devel/qapi-code-gen.rst