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
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:
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
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
© 2016 - 2025 Red Hat, Inc.