Extend the VirtioDeviceFeatures struct with an additional u64
to track unknown features in the 64-127 bit range and decode
the full virtio features spaces for vhost and virtio devices.
Also add entries for the soon-to-be-supported virtio net GSO over
UDP features.
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
---
v2 -> v3:
- unknown-dev-features-dword2 -> unknown-dev-features2
- _array -> _ex
- fixed typos in entries description
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..1daae482d3 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_features2,
features->unknown_dev_features);
}
}
diff --git a/hw/virtio/virtio-qmp.c b/hw/virtio/virtio-qmp.c
index 3b6377cf0d..03c6163cf4 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_HOST_UDP_TUNNEL_GSO: Device can receive GSO over "
+ "UDP tunnel packets"),
+ FEATURE_ENTRY(VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO_CSUM, \
+ "VIRTIO_NET_F_HOST_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_empty(bitmap);
if (features->has_unknown_dev_features) {
- features->unknown_dev_features = bitmap;
+ features->unknown_dev_features = bitmap[0];
+ features->unknown_dev_features2 = 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_ex);
status->host_features = qmp_decode_features(vdev->device_id,
- vdev->host_features);
+ vdev->host_features_ex);
status->backend_features = qmp_decode_features(vdev->device_id,
- vdev->backend_features);
+ vdev->backend_features_ex);
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_ex);
status->vhost_dev->acked_features =
- qmp_decode_features(vdev->device_id, hdev->acked_features);
+ qmp_decode_features(vdev->device_id, hdev->acked_features_ex);
status->vhost_dev->backend_features =
- qmp_decode_features(vdev->device_id, hdev->backend_features);
+ qmp_decode_features(vdev->device_id, hdev->backend_features_ex);
+
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 9d652fe4a8..f2e2dd6e97 100644
--- a/qapi/virtio.json
+++ b/qapi/virtio.json
@@ -490,14 +490,18 @@
# unique features)
#
# @unknown-dev-features: Virtio device features bitmap that have not
-# been decoded
+# been decoded (bits 0-63)
+#
+# @unknown-dev-features2: Virtio device features bitmap that have not
+# been decoded (bits 64-127)
#
# Since: 7.2
##
{ 'struct': 'VirtioDeviceFeatures',
'data': { 'transports': [ 'str' ],
'*dev-features': [ 'str' ],
- '*unknown-dev-features': 'uint64' } }
+ '*unknown-dev-features': 'uint64',
+ '*unknown-dev-features2': 'uint64' } }
##
# @VirtQueueStatus:
--
2.50.0
On 2025/07/18 17:52, Paolo Abeni wrote:
> Extend the VirtioDeviceFeatures struct with an additional u64
> to track unknown features in the 64-127 bit range and decode
> the full virtio features spaces for vhost and virtio devices.
>
> Also add entries for the soon-to-be-supported virtio net GSO over
> UDP features.
>
> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
> ---
> v2 -> v3:
> - unknown-dev-features-dword2 -> unknown-dev-features2
> - _array -> _ex
> - fixed typos in entries description
>
> 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..1daae482d3 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_features2,
> features->unknown_dev_features);
> }
> }
> diff --git a/hw/virtio/virtio-qmp.c b/hw/virtio/virtio-qmp.c
> index 3b6377cf0d..03c6163cf4 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_HOST_UDP_TUNNEL_GSO: Device can receive GSO over "
> + "UDP tunnel packets"),
> + FEATURE_ENTRY(VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO_CSUM, \
> + "VIRTIO_NET_F_HOST_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_empty(bitmap);
> if (features->has_unknown_dev_features) {
> - features->unknown_dev_features = bitmap;
> + features->unknown_dev_features = bitmap[0];
> + features->unknown_dev_features2 = 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_ex);
> status->host_features = qmp_decode_features(vdev->device_id,
> - vdev->host_features);
> + vdev->host_features_ex);
> status->backend_features = qmp_decode_features(vdev->device_id,
> - vdev->backend_features);
> + vdev->backend_features_ex);
>
> 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_ex);
> status->vhost_dev->acked_features =
> - qmp_decode_features(vdev->device_id, hdev->acked_features);
> + qmp_decode_features(vdev->device_id, hdev->acked_features_ex);
> status->vhost_dev->backend_features =
> - qmp_decode_features(vdev->device_id, hdev->backend_features);
> + qmp_decode_features(vdev->device_id, hdev->backend_features_ex);
> +
> 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 9d652fe4a8..f2e2dd6e97 100644
> --- a/qapi/virtio.json
> +++ b/qapi/virtio.json
> @@ -490,14 +490,18 @@
> # unique features)
> #
> # @unknown-dev-features: Virtio device features bitmap that have not
> -# been decoded
> +# been decoded (bits 0-63)
> +#
> +# @unknown-dev-features2: Virtio device features bitmap that have not
> +# been decoded (bits 64-127)
This documentation should contain "(since 10.1)" as described in:
docs/devel/qapi-code-gen.rst
> #
> # Since: 7.2
> ##
> { 'struct': 'VirtioDeviceFeatures',
> 'data': { 'transports': [ 'str' ],
> '*dev-features': [ 'str' ],
> - '*unknown-dev-features': 'uint64' } }
> + '*unknown-dev-features': 'uint64',
> + '*unknown-dev-features2': 'uint64' } }
>
> ##
> # @VirtQueueStatus:
On 7/21/25 9:23 AM, Akihiko Odaki wrote:
> On 2025/07/18 17:52, Paolo Abeni wrote:
>> Extend the VirtioDeviceFeatures struct with an additional u64
>> to track unknown features in the 64-127 bit range and decode
>> the full virtio features spaces for vhost and virtio devices.
>>
>> Also add entries for the soon-to-be-supported virtio net GSO over
>> UDP features.
>>
>> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
>> ---
>> v2 -> v3:
>> - unknown-dev-features-dword2 -> unknown-dev-features2
>> - _array -> _ex
>> - fixed typos in entries description
>>
>> 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..1daae482d3 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_features2,
>> features->unknown_dev_features);
>> }
>> }
>> diff --git a/hw/virtio/virtio-qmp.c b/hw/virtio/virtio-qmp.c
>> index 3b6377cf0d..03c6163cf4 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_HOST_UDP_TUNNEL_GSO: Device can receive GSO over "
>> + "UDP tunnel packets"),
>> + FEATURE_ENTRY(VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO_CSUM, \
>> + "VIRTIO_NET_F_HOST_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_empty(bitmap);
>> if (features->has_unknown_dev_features) {
>> - features->unknown_dev_features = bitmap;
>> + features->unknown_dev_features = bitmap[0];
>> + features->unknown_dev_features2 = 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_ex);
>> status->host_features = qmp_decode_features(vdev->device_id,
>> - vdev->host_features);
>> + vdev->host_features_ex);
>> status->backend_features = qmp_decode_features(vdev->device_id,
>> - vdev->backend_features);
>> + vdev->backend_features_ex);
>>
>> 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_ex);
>> status->vhost_dev->acked_features =
>> - qmp_decode_features(vdev->device_id, hdev->acked_features);
>> + qmp_decode_features(vdev->device_id, hdev->acked_features_ex);
>> status->vhost_dev->backend_features =
>> - qmp_decode_features(vdev->device_id, hdev->backend_features);
>> + qmp_decode_features(vdev->device_id, hdev->backend_features_ex);
>> +
>> 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 9d652fe4a8..f2e2dd6e97 100644
>> --- a/qapi/virtio.json
>> +++ b/qapi/virtio.json
>> @@ -490,14 +490,18 @@
>> # unique features)
>> #
>> # @unknown-dev-features: Virtio device features bitmap that have not
>> -# been decoded
>> +# been decoded (bits 0-63)
>> +#
>> +# @unknown-dev-features2: Virtio device features bitmap that have not
>> +# been decoded (bits 64-127)
>
> This documentation should contain "(since 10.1)" as described in:
> docs/devel/qapi-code-gen.rst
Just to be pedant, since there is a little ambiguity between the
examples in docs/devel/qapi-code-gen.rst and the actual code e.g. in
qapi/qom.json, I'll use:
# @unknown-dev-features2: Virtio device features bitmap that have not
# been decoded (bits 64-127) (since 10.2)
/P
On Mon, Jul 21, 2025 at 04:23:14PM +0900, Akihiko Odaki wrote: >On 2025/07/18 17:52, Paolo Abeni wrote: >>Extend the VirtioDeviceFeatures struct with an additional u64 >>to track unknown features in the 64-127 bit range and decode >>the full virtio features spaces for vhost and virtio devices. >> >>Also add entries for the soon-to-be-supported virtio net GSO over >>UDP features. >> >>Signed-off-by: Paolo Abeni <pabeni@redhat.com> >>--- >>v2 -> v3: >> - unknown-dev-features-dword2 -> unknown-dev-features2 >> - _array -> _ex >> - fixed typos in entries description >> >>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/qapi/virtio.json b/qapi/virtio.json >>index 9d652fe4a8..f2e2dd6e97 100644 >>--- a/qapi/virtio.json >>+++ b/qapi/virtio.json >>@@ -490,14 +490,18 @@ >> # unique features) >> # >> # @unknown-dev-features: Virtio device features bitmap that have not >>-# been decoded >>+# been decoded (bits 0-63) >>+# >>+# @unknown-dev-features2: Virtio device features bitmap that have not >>+# been decoded (bits 64-127) > >This documentation should contain "(since 10.1)" as described in: >docs/devel/qapi-code-gen.rst Good catch! BTW 10.1 is already in soft-freeze, so I guess this will land in the next cycle, so I'd suggest to use 10.2 Thanks, Stefano
Paolo Abeni <pabeni@redhat.com> writes:
> Extend the VirtioDeviceFeatures struct with an additional u64
> to track unknown features in the 64-127 bit range and decode
> the full virtio features spaces for vhost and virtio devices.
>
> Also add entries for the soon-to-be-supported virtio net GSO over
> UDP features.
>
> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
[...]
> diff --git a/hw/virtio/virtio-qmp.c b/hw/virtio/virtio-qmp.c
> index 3b6377cf0d..03c6163cf4 100644
> --- a/hw/virtio/virtio-qmp.c
> +++ b/hw/virtio/virtio-qmp.c
[...]
> @@ -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_empty(bitmap);
> if (features->has_unknown_dev_features) {
> - features->unknown_dev_features = bitmap;
> + features->unknown_dev_features = bitmap[0];
> + features->unknown_dev_features2 = bitmap[1];
> }
Why not assign unconditionally?
>
> return features;
[...]
> diff --git a/qapi/virtio.json b/qapi/virtio.json
> index 9d652fe4a8..f2e2dd6e97 100644
> --- a/qapi/virtio.json
> +++ b/qapi/virtio.json
> @@ -490,14 +490,18 @@
> # unique features)
> #
> # @unknown-dev-features: Virtio device features bitmap that have not
> -# been decoded
> +# been decoded (bits 0-63)
> +#
> +# @unknown-dev-features2: Virtio device features bitmap that have not
> +# been decoded (bits 64-127)
> #
> # Since: 7.2
> ##
> { 'struct': 'VirtioDeviceFeatures',
> 'data': { 'transports': [ 'str' ],
> '*dev-features': [ 'str' ],
> - '*unknown-dev-features': 'uint64' } }
> + '*unknown-dev-features': 'uint64',
> + '*unknown-dev-features2': 'uint64' } }
>
> ##
> # @VirtQueueStatus:
I wish we could simply widen @unknown-dev-features, but we don't have
uint128, and adding it would risk breaking QMP clients. 64 bit integers
are already troublesome in JSON.
Does the example in x-query-virtio-status's doc comment need an update?
On 7/19/25 8:57 AM, Markus Armbruster wrote:
> Paolo Abeni <pabeni@redhat.com> writes:
>
>> Extend the VirtioDeviceFeatures struct with an additional u64
>> to track unknown features in the 64-127 bit range and decode
>> the full virtio features spaces for vhost and virtio devices.
>>
>> Also add entries for the soon-to-be-supported virtio net GSO over
>> UDP features.
>>
>> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
>
> [...]
>
>> diff --git a/hw/virtio/virtio-qmp.c b/hw/virtio/virtio-qmp.c
>> index 3b6377cf0d..03c6163cf4 100644
>> --- a/hw/virtio/virtio-qmp.c
>> +++ b/hw/virtio/virtio-qmp.c
>
> [...]
>
>> @@ -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_empty(bitmap);
>> if (features->has_unknown_dev_features) {
>> - features->unknown_dev_features = bitmap;
>> + features->unknown_dev_features = bitmap[0];
>> + features->unknown_dev_features2 = bitmap[1];
>> }
>
> Why not assign unconditionally?
I stuck with the old/previous code style. I can move to unconditional
assignment in the next revision.
>> return features;
>
> [...]
>
>> diff --git a/qapi/virtio.json b/qapi/virtio.json
>> index 9d652fe4a8..f2e2dd6e97 100644
>> --- a/qapi/virtio.json
>> +++ b/qapi/virtio.json
>> @@ -490,14 +490,18 @@
>> # unique features)
>> #
>> # @unknown-dev-features: Virtio device features bitmap that have not
>> -# been decoded
>> +# been decoded (bits 0-63)
>> +#
>> +# @unknown-dev-features2: Virtio device features bitmap that have not
>> +# been decoded (bits 64-127)
>> #
>> # Since: 7.2
>> ##
>> { 'struct': 'VirtioDeviceFeatures',
>> 'data': { 'transports': [ 'str' ],
>> '*dev-features': [ 'str' ],
>> - '*unknown-dev-features': 'uint64' } }
>> + '*unknown-dev-features': 'uint64',
>> + '*unknown-dev-features2': 'uint64' } }
>>
>> ##
>> # @VirtQueueStatus:
>
> I wish we could simply widen @unknown-dev-features, but we don't have
> uint128, and adding it would risk breaking QMP clients. 64 bit integers
> are already troublesome in JSON.
>
> Does the example in x-query-virtio-status's doc comment need an update?
Yes, you are right, the output for the 'unknown features' field will
include leading zeros for the high 64 bits.
I will update it in the next revision, thanks!
Paolo
On Fri, Jul 18, 2025 at 10:52:34AM +0200, Paolo Abeni wrote:
>Extend the VirtioDeviceFeatures struct with an additional u64
>to track unknown features in the 64-127 bit range and decode
>the full virtio features spaces for vhost and virtio devices.
>
>Also add entries for the soon-to-be-supported virtio net GSO over
>UDP features.
>
>Signed-off-by: Paolo Abeni <pabeni@redhat.com>
>---
>v2 -> v3:
> - unknown-dev-features-dword2 -> unknown-dev-features2
> - _array -> _ex
> - fixed typos in entries description
>
>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..1daae482d3 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_features2,
> features->unknown_dev_features);
> }
> }
>diff --git a/hw/virtio/virtio-qmp.c b/hw/virtio/virtio-qmp.c
>index 3b6377cf0d..03c6163cf4 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_HOST_UDP_TUNNEL_GSO: Device can receive GSO over "
>+ "UDP tunnel packets"),
>+ FEATURE_ENTRY(VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO_CSUM, \
>+ "VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO: Device can receive GSO over "
>+ "UDP tunnel packets requiring checksum offload for the outer "
>+ "header"),
Is this chunk supposed to be here in this patch or better in the last
patches where you add UPD tunnel features support?
Thanks,
Stefano
> { -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_empty(bitmap);
> if (features->has_unknown_dev_features) {
>- features->unknown_dev_features = bitmap;
>+ features->unknown_dev_features = bitmap[0];
>+ features->unknown_dev_features2 = 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_ex);
> status->host_features = qmp_decode_features(vdev->device_id,
>- vdev->host_features);
>+ vdev->host_features_ex);
> status->backend_features = qmp_decode_features(vdev->device_id,
>- vdev->backend_features);
>+ vdev->backend_features_ex);
>
> 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_ex);
> status->vhost_dev->acked_features =
>- qmp_decode_features(vdev->device_id, hdev->acked_features);
>+ qmp_decode_features(vdev->device_id, hdev->acked_features_ex);
> status->vhost_dev->backend_features =
>- qmp_decode_features(vdev->device_id, hdev->backend_features);
>+ qmp_decode_features(vdev->device_id, hdev->backend_features_ex);
>+
> 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 9d652fe4a8..f2e2dd6e97 100644
>--- a/qapi/virtio.json
>+++ b/qapi/virtio.json
>@@ -490,14 +490,18 @@
> # unique features)
> #
> # @unknown-dev-features: Virtio device features bitmap that have not
>-# been decoded
>+# been decoded (bits 0-63)
>+#
>+# @unknown-dev-features2: Virtio device features bitmap that have not
>+# been decoded (bits 64-127)
> #
> # Since: 7.2
> ##
> { 'struct': 'VirtioDeviceFeatures',
> 'data': { 'transports': [ 'str' ],
> '*dev-features': [ 'str' ],
>- '*unknown-dev-features': 'uint64' } }
>+ '*unknown-dev-features': 'uint64',
>+ '*unknown-dev-features2': 'uint64' } }
>
> ##
> # @VirtQueueStatus:
>--
>2.50.0
>
On 7/18/25 12:18 PM, Stefano Garzarella wrote:
> On Fri, Jul 18, 2025 at 10:52:34AM +0200, Paolo Abeni wrote:
>> diff --git a/hw/virtio/virtio-qmp.c b/hw/virtio/virtio-qmp.c
>> index 3b6377cf0d..03c6163cf4 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_HOST_UDP_TUNNEL_GSO: Device can receive GSO over "
>> + "UDP tunnel packets"),
>> + FEATURE_ENTRY(VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO_CSUM, \
>> + "VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO: Device can receive GSO over "
>> + "UDP tunnel packets requiring checksum offload for the outer "
>> + "header"),
>
> Is this chunk supposed to be here in this patch or better in the last
> patches where you add UPD tunnel features support?
Note that this point was discussed in the previous iteration:
https://lists.gnu.org/archive/html/qemu-devel/2025-07/msg04418.html
I think it could be both way: it could be useful for QMP to be able to
dump the (kernel/backend) features in human readable format even if qemu
does not support them.
No big objection to move the above chunk in patch 13/13, if there is
agreement :)
/P
On Fri, Jul 18, 2025 at 12:23:21PM +0200, Paolo Abeni wrote:
>On 7/18/25 12:18 PM, Stefano Garzarella wrote:
>> On Fri, Jul 18, 2025 at 10:52:34AM +0200, Paolo Abeni wrote:
>>> diff --git a/hw/virtio/virtio-qmp.c b/hw/virtio/virtio-qmp.c
>>> index 3b6377cf0d..03c6163cf4 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_HOST_UDP_TUNNEL_GSO: Device can receive GSO over "
>>> + "UDP tunnel packets"),
>>> + FEATURE_ENTRY(VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO_CSUM, \
>>> + "VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO: Device can receive GSO over "
>>> + "UDP tunnel packets requiring checksum offload for the outer "
>>> + "header"),
>>
>> Is this chunk supposed to be here in this patch or better in the last
>> patches where you add UPD tunnel features support?
>
>Note that this point was discussed in the previous iteration:
>
>https://lists.gnu.org/archive/html/qemu-devel/2025-07/msg04418.html
Ops, sorry, I skiped that version and came directly here.
I'll check the v3.
>
>I think it could be both way: it could be useful for QMP to be able to
>dump the (kernel/backend) features in human readable format even if qemu
>does not support them.
I see.
>
>No big objection to move the above chunk in patch 13/13, if there is
>agreement :)
Not a strong opinion here.
Thanks,
Stefano
© 2016 - 2025 Red Hat, Inc.