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