qmp: update virtio features map to support extended features

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.

Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
Acked-by: Jason Wang <jasowang@redhat.com>
Acked-by: Markus Armbruster <armbru@redhat.com>
Acked-by: Stefano Garzarella <sgarzare@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Tested-by: Lei Yang <leiyang@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <e51969f94d89045b333f1bc5ef5fca9e12fc371a.1758549625.git.pabeni@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Paolo Abeni
2025-09-22 16:18:23 +02:00
committed by Michael S. Tsirkin
parent 9f979ef0e0
commit a76f5b795c
4 changed files with 74 additions and 32 deletions

View File

@@ -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);
}
}

View File

@@ -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_CSUM: 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_NU64S];
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,10 +715,9 @@ VirtioDeviceFeatures *qmp_decode_features(uint16_t device_id, uint64_t bitmap)
g_assert_not_reached();
}
features->has_unknown_dev_features = bitmap != 0;
if (features->has_unknown_dev_features) {
features->unknown_dev_features = bitmap;
}
features->has_unknown_dev_features = !virtio_features_empty(bitmap);
features->unknown_dev_features = bitmap[0];
features->unknown_dev_features2 = bitmap[1];
return features;
}
@@ -743,11 +777,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 +819,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;

View File

@@ -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

View File

@@ -247,6 +247,7 @@
# },
# "host-features": {
# "unknown-dev-features": 1073741824,
# "unknown-dev-features2": 0,
# "dev-features": [],
# "transports": [
# "VIRTIO_RING_F_EVENT_IDX: Used & avail. event fields enabled",
@@ -490,14 +491,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 10.2)
#
# Since: 7.2
##
{ 'struct': 'VirtioDeviceFeatures',
'data': { 'transports': [ 'str' ],
'*dev-features': [ 'str' ],
'*unknown-dev-features': 'uint64' } }
'*unknown-dev-features': 'uint64',
'*unknown-dev-features2': 'uint64' } }
##
# @VirtQueueStatus: