On Fri, Sep 12, 2025 at 03:07:00PM +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.
> 
> Reviewed-by: Akihiko Odaki <[email protected]>
> Acked-by: Jason Wang <[email protected]>
> Signed-off-by: Paolo Abeni <[email protected]>
> ---
> v3 -> v4:
>   - cleanup unknown features init
>   - update QMP example and doc accordingly
>   - use new virtio_features macro names
> 
> 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      | 91 +++++++++++++++++++++++++------------
>  hw/virtio/virtio-qmp.h      |  3 +-
>  qapi/virtio.json            |  9 +++-
>  4 files changed, 74 insertions(+), 32 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..502c9ae930 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 "

This really should be VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO_CSUM.

Given they all seem to start with repeating the feature name,
why not just add it to the string automatically by the macro?


> +            "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_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;
> 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..05295ab665 100644
> --- a/qapi/virtio.json
> +++ b/qapi/virtio.json
> @@ -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:
> -- 
> 2.51.0


Reply via email to