diff mbox series

[v4,1/2] virtio: introduce `query-virtio' QMP command

Message ID 1507034861-4661-2-git-send-email-jan.dakinevich@virtuozzo.com
State New
Headers show
Series virtio: introduce `info virtio' hmp command | expand

Commit Message

Jan Dakinevich Oct. 3, 2017, 12:47 p.m. UTC
The command is intended for gathering virtio information such as status,
feature bits, negotiation status. It is convenient and useful for debug
purpose.

The commands returns generic virtio information for virtio such as
common feature names and status bits names and information for all
attached to current machine devices.

To retrieve names of device-specific features `get_feature_name'
callback in VirtioDeviceClass also was introduced.

Cc: Denis V. Lunev <den@virtuozzo.com>
Signed-off-by: Jan Dakinevich <jan.dakinevich@virtuozzo.com>
---
 hw/block/virtio-blk.c       |  21 +++++++++
 hw/char/virtio-serial-bus.c |  15 +++++++
 hw/display/virtio-gpu.c     |  13 ++++++
 hw/net/virtio-net.c         |  35 +++++++++++++++
 hw/scsi/virtio-scsi.c       |  16 +++++++
 hw/virtio/Makefile.objs     |   2 +
 hw/virtio/virtio-balloon.c  |  15 +++++++
 hw/virtio/virtio-stub.c     |   9 ++++
 hw/virtio/virtio.c          | 101 ++++++++++++++++++++++++++++++++++++++++++++
 include/hw/virtio/virtio.h  |   2 +
 qapi-schema.json            |   1 +
 qapi/virtio.json            |  94 +++++++++++++++++++++++++++++++++++++++++
 12 files changed, 324 insertions(+)
 create mode 100644 hw/virtio/virtio-stub.c
 create mode 100644 qapi/virtio.json

Comments

Eric Blake Oct. 3, 2017, 2:02 p.m. UTC | #1
On 10/03/2017 07:47 AM, Jan Dakinevich wrote:
> The command is intended for gathering virtio information such as status,
> feature bits, negotiation status. It is convenient and useful for debug
> purpose.
> 
> The commands returns generic virtio information for virtio such as
> common feature names and status bits names and information for all
> attached to current machine devices.
> 
> To retrieve names of device-specific features `get_feature_name'
> callback in VirtioDeviceClass also was introduced.
> 
> Cc: Denis V. Lunev <den@virtuozzo.com>
> Signed-off-by: Jan Dakinevich <jan.dakinevich@virtuozzo.com>
> ---
>  hw/block/virtio-blk.c       |  21 +++++++++
>  hw/char/virtio-serial-bus.c |  15 +++++++
>  hw/display/virtio-gpu.c     |  13 ++++++
>  hw/net/virtio-net.c         |  35 +++++++++++++++
>  hw/scsi/virtio-scsi.c       |  16 +++++++
>  hw/virtio/Makefile.objs     |   2 +
>  hw/virtio/virtio-balloon.c  |  15 +++++++
>  hw/virtio/virtio-stub.c     |   9 ++++
>  hw/virtio/virtio.c          | 101 ++++++++++++++++++++++++++++++++++++++++++++
>  include/hw/virtio/virtio.h  |   2 +
>  qapi-schema.json            |   1 +
>  qapi/virtio.json            |  94 +++++++++++++++++++++++++++++++++++++++++
>  12 files changed, 324 insertions(+)
>  create mode 100644 hw/virtio/virtio-stub.c
>  create mode 100644 qapi/virtio.json

This creates a new .json file, but does not touch MAINTAINERS.  Our idea
in splitting the .json files was to make it easier for each sub-file
that needs a specific maintainer in addition to the overall *.json line
for QAPI maintainers, so this may deserve a MAINTAINERS entry.


> +++ b/qapi/virtio.json
> @@ -0,0 +1,94 @@
> +# -*- Mode: Python -*-
> +#
> +
> +##
> +# = Virtio devices
> +##
> +
> +{ 'include': 'common.json' }
> +
> +##
> +# @VirtioInfoBit:
> +#
> +# Named virtio bit
> +#
> +# @bit: bit number
> +#
> +# @name: bit name
> +#
> +# Since: 2.11.0
> +#
> +##
> +{
> +    'struct': 'VirtioInfoBit',
> +    'data': {
> +        'bit': 'uint64',

Why is this a 64-bit value? Are the values 0-63, or are they 1, 2, 4, 8,
...?  The documentation on 'bit number' is rather sparse.

> +        'name': 'str'

Wouldn't an enum type be better than an open-ended string?

> +    }
> +}
> +
> +##
> +# @VirtioInfoDevice:
> +#
> +# Information about specific virtio device
> +#
> +# @qom_path: QOM path of the device

Please make this 'qom-path' - new interfaces should prefer '-' over '_'.

> +#
> +# @feature-names: names of device-specific features
> +#
> +# @host-features: bitmask of features, provided by devices
> +#
> +# @guest-features: bitmask of features, acknowledged by guest
> +#
> +# @status: virtio device status bitmask
> +#
> +# Since: 2.11.0
> +#
> +##
> +{
> +    'struct': 'VirtioInfoDevice',
> +    'data': {
> +        'qom_path': 'str',
> +        'feature-names': ['VirtioInfoBit'],
> +        'host-features': 'uint64',
> +        'guest-features': 'uint64',
> +        'status': 'uint64'

I'm wondering if this is the best representation (where the caller has
to parse the integer and then lookup in feature-names what each bit of
the integer represents).  But I'm not sure I have anything better off
the top of my head.

> +    }
> +}
> +
> +##
> +# @VirtioInfo:
> +#
> +# Information about virtio devices
> +#
> +# @feature-names: names of common virtio features
> +#
> +# @status-names: names of bits which represents virtio device status
> +#
> +# @devices: list of per-device virtio information
> +#
> +# Since: 2.11.0
> +#
> +##
> +{
> +    'struct': 'VirtioInfo',
> +    'data': {
> +        'feature-names': ['VirtioInfoBit'],

Why is feature-names listed at two different nestings of the return value?

> +        'status-names': ['VirtioInfoBit'],
> +        'devices': ['VirtioInfoDevice']
> +    }
> +}
> +
> +
> +##
> +# @query-virtio:
> +#
> +# Returns generic and per-device virtio information
> +#
> +# Since: 2.11.0
> +#
> +##
> +{
> +    'command': 'query-virtio',
> +    'returns': 'VirtioInfo'
> +}
>
Jan Dakinevich Oct. 3, 2017, 2:32 p.m. UTC | #2
On 10/03/2017 05:02 PM, Eric Blake wrote:
> On 10/03/2017 07:47 AM, Jan Dakinevich wrote:
>> The command is intended for gathering virtio information such as status,
>> feature bits, negotiation status. It is convenient and useful for debug
>> purpose.
>>
>> The commands returns generic virtio information for virtio such as
>> common feature names and status bits names and information for all
>> attached to current machine devices.
>>
>> To retrieve names of device-specific features `get_feature_name'
>> callback in VirtioDeviceClass also was introduced.
>>
>> Cc: Denis V. Lunev <den@virtuozzo.com>
>> Signed-off-by: Jan Dakinevich <jan.dakinevich@virtuozzo.com>
>> ---
>>  hw/block/virtio-blk.c       |  21 +++++++++
>>  hw/char/virtio-serial-bus.c |  15 +++++++
>>  hw/display/virtio-gpu.c     |  13 ++++++
>>  hw/net/virtio-net.c         |  35 +++++++++++++++
>>  hw/scsi/virtio-scsi.c       |  16 +++++++
>>  hw/virtio/Makefile.objs     |   2 +
>>  hw/virtio/virtio-balloon.c  |  15 +++++++
>>  hw/virtio/virtio-stub.c     |   9 ++++
>>  hw/virtio/virtio.c          | 101 ++++++++++++++++++++++++++++++++++++++++++++
>>  include/hw/virtio/virtio.h  |   2 +
>>  qapi-schema.json            |   1 +
>>  qapi/virtio.json            |  94 +++++++++++++++++++++++++++++++++++++++++
>>  12 files changed, 324 insertions(+)
>>  create mode 100644 hw/virtio/virtio-stub.c
>>  create mode 100644 qapi/virtio.json
> 
> This creates a new .json file, but does not touch MAINTAINERS.  Our idea
> in splitting the .json files was to make it easier for each sub-file
> that needs a specific maintainer in addition to the overall *.json line
> for QAPI maintainers, so this may deserve a MAINTAINERS entry.
> 

Ok.

>> +++ b/qapi/virtio.json
>> @@ -0,0 +1,94 @@
>> +# -*- Mode: Python -*-
>> +#
>> +
>> +##
>> +# = Virtio devices
>> +##
>> +
>> +{ 'include': 'common.json' }
>> +
>> +##
>> +# @VirtioInfoBit:
>> +#
>> +# Named virtio bit
>> +#
>> +# @bit: bit number
>> +#
>> +# @name: bit name
>> +#
>> +# Since: 2.11.0
>> +#
>> +##
>> +{
>> +    'struct': 'VirtioInfoBit',
>> +    'data': {
>> +        'bit': 'uint64',
> 
> Why is this a 64-bit value? Are the values 0-63, or are they 1, 2, 4, 8,
> ...?  The documentation on 'bit number' is rather sparse.

I would prefer `uint' here, but I don't see generic unsigned type (may
be, I am mistaken). I could use uint8 here, though.

> 
>> +        'name': 'str'
> 
> Wouldn't an enum type be better than an open-ended string?
> 

Bit names are not known here, they are obtained from virtio device
implementations.

>> +    }
>> +}
>> +
>> +##
>> +# @VirtioInfoDevice:
>> +#
>> +# Information about specific virtio device
>> +#
>> +# @qom_path: QOM path of the device
> 
> Please make this 'qom-path' - new interfaces should prefer '-' over '_'.

Ok.

>> +#
>> +# @feature-names: names of device-specific features
>> +#
>> +# @host-features: bitmask of features, provided by devices
>> +#
>> +# @guest-features: bitmask of features, acknowledged by guest
>> +#
>> +# @status: virtio device status bitmask
>> +#
>> +# Since: 2.11.0
>> +#
>> +##
>> +{
>> +    'struct': 'VirtioInfoDevice',
>> +    'data': {
>> +        'qom_path': 'str',
>> +        'feature-names': ['VirtioInfoBit'],
>> +        'host-features': 'uint64',
>> +        'guest-features': 'uint64',
>> +        'status': 'uint64'
> 
> I'm wondering if this is the best representation (where the caller has
> to parse the integer and then lookup in feature-names what each bit of
> the integer represents).  But I'm not sure I have anything better off
> the top of my head.
> 

Consider it as way to tell caller about names of supported features.

>> +    }
>> +}
>> +
>> +##
>> +# @VirtioInfo:
>> +#
>> +# Information about virtio devices
>> +#
>> +# @feature-names: names of common virtio features
>> +#
>> +# @status-names: names of bits which represents virtio device status
>> +#
>> +# @devices: list of per-device virtio information
>> +#
>> +# Since: 2.11.0
>> +#
>> +##
>> +{
>> +    'struct': 'VirtioInfo',
>> +    'data': {
>> +        'feature-names': ['VirtioInfoBit'],
> 
> Why is feature-names listed at two different nestings of the return value?
> 

These are different feature names. First names are common and predefined
for all devices. Second names are device-specific.

>> +        'status-names': ['VirtioInfoBit'],
>> +        'devices': ['VirtioInfoDevice']
>> +    }
>> +}
>> +
>> +
>> +##
>> +# @query-virtio:
>> +#
>> +# Returns generic and per-device virtio information
>> +#
>> +# Since: 2.11.0
>> +#
>> +##
>> +{
>> +    'command': 'query-virtio',
>> +    'returns': 'VirtioInfo'
>> +}
>>
>
Dr. David Alan Gilbert Oct. 3, 2017, 4:29 p.m. UTC | #3
* Jan Dakinevich (jan.dakinevich@virtuozzo.com) wrote:
> 
> 
> On 10/03/2017 05:02 PM, Eric Blake wrote:
> > On 10/03/2017 07:47 AM, Jan Dakinevich wrote:
> >> The command is intended for gathering virtio information such as status,
> >> feature bits, negotiation status. It is convenient and useful for debug
> >> purpose.
> >>
> >> The commands returns generic virtio information for virtio such as
> >> common feature names and status bits names and information for all
> >> attached to current machine devices.
> >>
> >> To retrieve names of device-specific features `get_feature_name'
> >> callback in VirtioDeviceClass also was introduced.
> >>
> >> Cc: Denis V. Lunev <den@virtuozzo.com>
> >> Signed-off-by: Jan Dakinevich <jan.dakinevich@virtuozzo.com>
> >> ---
> >>  hw/block/virtio-blk.c       |  21 +++++++++
> >>  hw/char/virtio-serial-bus.c |  15 +++++++
> >>  hw/display/virtio-gpu.c     |  13 ++++++
> >>  hw/net/virtio-net.c         |  35 +++++++++++++++
> >>  hw/scsi/virtio-scsi.c       |  16 +++++++
> >>  hw/virtio/Makefile.objs     |   2 +
> >>  hw/virtio/virtio-balloon.c  |  15 +++++++
> >>  hw/virtio/virtio-stub.c     |   9 ++++
> >>  hw/virtio/virtio.c          | 101 ++++++++++++++++++++++++++++++++++++++++++++
> >>  include/hw/virtio/virtio.h  |   2 +
> >>  qapi-schema.json            |   1 +
> >>  qapi/virtio.json            |  94 +++++++++++++++++++++++++++++++++++++++++
> >>  12 files changed, 324 insertions(+)
> >>  create mode 100644 hw/virtio/virtio-stub.c
> >>  create mode 100644 qapi/virtio.json
> > 
> > This creates a new .json file, but does not touch MAINTAINERS.  Our idea
> > in splitting the .json files was to make it easier for each sub-file
> > that needs a specific maintainer in addition to the overall *.json line
> > for QAPI maintainers, so this may deserve a MAINTAINERS entry.
> > 
> 
> Ok.
> 
> >> +++ b/qapi/virtio.json
> >> @@ -0,0 +1,94 @@
> >> +# -*- Mode: Python -*-
> >> +#
> >> +
> >> +##
> >> +# = Virtio devices
> >> +##
> >> +
> >> +{ 'include': 'common.json' }
> >> +
> >> +##
> >> +# @VirtioInfoBit:
> >> +#
> >> +# Named virtio bit
> >> +#
> >> +# @bit: bit number
> >> +#
> >> +# @name: bit name
> >> +#
> >> +# Since: 2.11.0
> >> +#
> >> +##
> >> +{
> >> +    'struct': 'VirtioInfoBit',
> >> +    'data': {
> >> +        'bit': 'uint64',
> > 
> > Why is this a 64-bit value? Are the values 0-63, or are they 1, 2, 4, 8,
> > ...?  The documentation on 'bit number' is rather sparse.
> 
> I would prefer `uint' here, but I don't see generic unsigned type (may
> be, I am mistaken). I could use uint8 here, though.
> 
> > 
> >> +        'name': 'str'
> > 
> > Wouldn't an enum type be better than an open-ended string?
> > 
> 
> Bit names are not known here, they are obtained from virtio device
> implementations.
> 
> >> +    }
> >> +}
> >> +
> >> +##
> >> +# @VirtioInfoDevice:
> >> +#
> >> +# Information about specific virtio device
> >> +#
> >> +# @qom_path: QOM path of the device
> > 
> > Please make this 'qom-path' - new interfaces should prefer '-' over '_'.
> 
> Ok.
> 
> >> +#
> >> +# @feature-names: names of device-specific features
> >> +#
> >> +# @host-features: bitmask of features, provided by devices
> >> +#
> >> +# @guest-features: bitmask of features, acknowledged by guest
> >> +#
> >> +# @status: virtio device status bitmask
> >> +#
> >> +# Since: 2.11.0
> >> +#
> >> +##
> >> +{
> >> +    'struct': 'VirtioInfoDevice',
> >> +    'data': {
> >> +        'qom_path': 'str',
> >> +        'feature-names': ['VirtioInfoBit'],
> >> +        'host-features': 'uint64',
> >> +        'guest-features': 'uint64',
> >> +        'status': 'uint64'
> > 
> > I'm wondering if this is the best representation (where the caller has
> > to parse the integer and then lookup in feature-names what each bit of
> > the integer represents).  But I'm not sure I have anything better off
> > the top of my head.
> > 
> 
> Consider it as way to tell caller about names of supported features.
> 
> >> +    }
> >> +}
> >> +
> >> +##
> >> +# @VirtioInfo:
> >> +#
> >> +# Information about virtio devices
> >> +#
> >> +# @feature-names: names of common virtio features
> >> +#
> >> +# @status-names: names of bits which represents virtio device status
> >> +#
> >> +# @devices: list of per-device virtio information
> >> +#
> >> +# Since: 2.11.0
> >> +#
> >> +##
> >> +{
> >> +    'struct': 'VirtioInfo',
> >> +    'data': {
> >> +        'feature-names': ['VirtioInfoBit'],
> > 
> > Why is feature-names listed at two different nestings of the return value?
> > 
> 
> These are different feature names. First names are common and predefined
> for all devices. Second names are device-specific.

If you can turn these into enums (union'd enums?) then you might
be able to get rid of a lot of your array filling/naming conversion
boilerplate. (Not sure if it's worth it, but it's worth looking).

Dave

> >> +        'status-names': ['VirtioInfoBit'],
> >> +        'devices': ['VirtioInfoDevice']
> >> +    }
> >> +}
> >> +
> >> +
> >> +##
> >> +# @query-virtio:
> >> +#
> >> +# Returns generic and per-device virtio information
> >> +#
> >> +# Since: 2.11.0
> >> +#
> >> +##
> >> +{
> >> +    'command': 'query-virtio',
> >> +    'returns': 'VirtioInfo'
> >> +}
> >>
> > 
> 
> -- 
> Best regards
> Jan Dakinevich
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
Jan Dakinevich Oct. 4, 2017, 2:26 p.m. UTC | #4
On 10/03/2017 07:29 PM, Dr. David Alan Gilbert wrote:
> * Jan Dakinevich (jan.dakinevich@virtuozzo.com) wrote:
>>
>>
>> On 10/03/2017 05:02 PM, Eric Blake wrote:
>>> On 10/03/2017 07:47 AM, Jan Dakinevich wrote:
>>>> The command is intended for gathering virtio information such as status,
>>>> feature bits, negotiation status. It is convenient and useful for debug
>>>> purpose.
>>>>
>>>> The commands returns generic virtio information for virtio such as
>>>> common feature names and status bits names and information for all
>>>> attached to current machine devices.
>>>>
>>>> To retrieve names of device-specific features `get_feature_name'
>>>> callback in VirtioDeviceClass also was introduced.
>>>>
>>>> Cc: Denis V. Lunev <den@virtuozzo.com>
>>>> Signed-off-by: Jan Dakinevich <jan.dakinevich@virtuozzo.com>
>>>> ---
>>>>  hw/block/virtio-blk.c       |  21 +++++++++
>>>>  hw/char/virtio-serial-bus.c |  15 +++++++
>>>>  hw/display/virtio-gpu.c     |  13 ++++++
>>>>  hw/net/virtio-net.c         |  35 +++++++++++++++
>>>>  hw/scsi/virtio-scsi.c       |  16 +++++++
>>>>  hw/virtio/Makefile.objs     |   2 +
>>>>  hw/virtio/virtio-balloon.c  |  15 +++++++
>>>>  hw/virtio/virtio-stub.c     |   9 ++++
>>>>  hw/virtio/virtio.c          | 101 ++++++++++++++++++++++++++++++++++++++++++++
>>>>  include/hw/virtio/virtio.h  |   2 +
>>>>  qapi-schema.json            |   1 +
>>>>  qapi/virtio.json            |  94 +++++++++++++++++++++++++++++++++++++++++
>>>>  12 files changed, 324 insertions(+)
>>>>  create mode 100644 hw/virtio/virtio-stub.c
>>>>  create mode 100644 qapi/virtio.json
>>>
>>> This creates a new .json file, but does not touch MAINTAINERS.  Our idea
>>> in splitting the .json files was to make it easier for each sub-file
>>> that needs a specific maintainer in addition to the overall *.json line
>>> for QAPI maintainers, so this may deserve a MAINTAINERS entry.
>>>
>>
>> Ok.
>>
>>>> +++ b/qapi/virtio.json
>>>> @@ -0,0 +1,94 @@
>>>> +# -*- Mode: Python -*-
>>>> +#
>>>> +
>>>> +##
>>>> +# = Virtio devices
>>>> +##
>>>> +
>>>> +{ 'include': 'common.json' }
>>>> +
>>>> +##
>>>> +# @VirtioInfoBit:
>>>> +#
>>>> +# Named virtio bit
>>>> +#
>>>> +# @bit: bit number
>>>> +#
>>>> +# @name: bit name
>>>> +#
>>>> +# Since: 2.11.0
>>>> +#
>>>> +##
>>>> +{
>>>> +    'struct': 'VirtioInfoBit',
>>>> +    'data': {
>>>> +        'bit': 'uint64',
>>>
>>> Why is this a 64-bit value? Are the values 0-63, or are they 1, 2, 4, 8,
>>> ...?  The documentation on 'bit number' is rather sparse.
>>
>> I would prefer `uint' here, but I don't see generic unsigned type (may
>> be, I am mistaken). I could use uint8 here, though.
>>
>>>
>>>> +        'name': 'str'
>>>
>>> Wouldn't an enum type be better than an open-ended string?
>>>
>>
>> Bit names are not known here, they are obtained from virtio device
>> implementations.
>>
>>>> +    }
>>>> +}
>>>> +
>>>> +##
>>>> +# @VirtioInfoDevice:
>>>> +#
>>>> +# Information about specific virtio device
>>>> +#
>>>> +# @qom_path: QOM path of the device
>>>
>>> Please make this 'qom-path' - new interfaces should prefer '-' over '_'.
>>
>> Ok.
>>
>>>> +#
>>>> +# @feature-names: names of device-specific features
>>>> +#
>>>> +# @host-features: bitmask of features, provided by devices
>>>> +#
>>>> +# @guest-features: bitmask of features, acknowledged by guest
>>>> +#
>>>> +# @status: virtio device status bitmask
>>>> +#
>>>> +# Since: 2.11.0
>>>> +#
>>>> +##
>>>> +{
>>>> +    'struct': 'VirtioInfoDevice',
>>>> +    'data': {
>>>> +        'qom_path': 'str',
>>>> +        'feature-names': ['VirtioInfoBit'],
>>>> +        'host-features': 'uint64',
>>>> +        'guest-features': 'uint64',
>>>> +        'status': 'uint64'
>>>
>>> I'm wondering if this is the best representation (where the caller has
>>> to parse the integer and then lookup in feature-names what each bit of
>>> the integer represents).  But I'm not sure I have anything better off
>>> the top of my head.
>>>
>>
>> Consider it as way to tell caller about names of supported features.
>>
>>>> +    }
>>>> +}
>>>> +
>>>> +##
>>>> +# @VirtioInfo:
>>>> +#
>>>> +# Information about virtio devices
>>>> +#
>>>> +# @feature-names: names of common virtio features
>>>> +#
>>>> +# @status-names: names of bits which represents virtio device status
>>>> +#
>>>> +# @devices: list of per-device virtio information
>>>> +#
>>>> +# Since: 2.11.0
>>>> +#
>>>> +##
>>>> +{
>>>> +    'struct': 'VirtioInfo',
>>>> +    'data': {
>>>> +        'feature-names': ['VirtioInfoBit'],
>>>
>>> Why is feature-names listed at two different nestings of the return value?
>>>
>>
>> These are different feature names. First names are common and predefined
>> for all devices. Second names are device-specific.
> 
> If you can turn these into enums (union'd enums?) then you might
> be able to get rid of a lot of your array filling/naming conversion
> boilerplate. (Not sure if it's worth it, but it's worth looking).
> 

I would be happy to drop this boilerplate, but how enum could help here?
To respond my requirement it should be something like set, not enum.
Even so, having set, I would have been needed to declare mapping between
names in set type and bit numbers within feature bitmask.

> Dave
> 
>>>> +        'status-names': ['VirtioInfoBit'],
>>>> +        'devices': ['VirtioInfoDevice']
>>>> +    }
>>>> +}
>>>> +
>>>> +
>>>> +##
>>>> +# @query-virtio:
>>>> +#
>>>> +# Returns generic and per-device virtio information
>>>> +#
>>>> +# Since: 2.11.0
>>>> +#
>>>> +##
>>>> +{
>>>> +    'command': 'query-virtio',
>>>> +    'returns': 'VirtioInfo'
>>>> +}
>>>>
>>>
>>
>> -- 
>> Best regards
>> Jan Dakinevich
> --
> Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
>
Eric Blake Oct. 4, 2017, 4 p.m. UTC | #5
On 10/04/2017 09:26 AM, Jan Dakinevich wrote:

>>>>> +{
>>>>> +    'struct': 'VirtioInfo',
>>>>> +    'data': {
>>>>> +        'feature-names': ['VirtioInfoBit'],
>>>>
>>>> Why is feature-names listed at two different nestings of the return value?
>>>>
>>>
>>> These are different feature names. First names are common and predefined
>>> for all devices. Second names are device-specific.
>>
>> If you can turn these into enums (union'd enums?) then you might
>> be able to get rid of a lot of your array filling/naming conversion
>> boilerplate. (Not sure if it's worth it, but it's worth looking).
>>
> 
> I would be happy to drop this boilerplate, but how enum could help here?
> To respond my requirement it should be something like set, not enum.
> Even so, having set, I would have been needed to declare mapping between
> names in set type and bit numbers within feature bitmask.

Instead of returning a bitmask ("mask":123) as well as an array naming
those bits
([{"bit":1,"name":"bit1"},{"bit":2","name":"bit2"},{"bit":4,"name":"bit4},...]),
you could omit the bit numbers and just return an array of named bits
(["bit1", "bit2", "bit4"]).  An enum lets you declare up front what
named bits are supported (and code can introspect when new named bits
are supported in newer qemu).

Perhaps it's easier to first take a step back, and show what the desired
output might be like, and then we can figure out how to represent that
output in QAPI.
Jan Dakinevich Oct. 5, 2017, 4:55 p.m. UTC | #6
On 10/04/2017 07:00 PM, Eric Blake wrote:
> On 10/04/2017 09:26 AM, Jan Dakinevich wrote:
> 
>>>>>> +{
>>>>>> +    'struct': 'VirtioInfo',
>>>>>> +    'data': {
>>>>>> +        'feature-names': ['VirtioInfoBit'],
>>>>>
>>>>> Why is feature-names listed at two different nestings of the return value?
>>>>>
>>>>
>>>> These are different feature names. First names are common and predefined
>>>> for all devices. Second names are device-specific.
>>>
>>> If you can turn these into enums (union'd enums?) then you might
>>> be able to get rid of a lot of your array filling/naming conversion
>>> boilerplate. (Not sure if it's worth it, but it's worth looking).
>>>
>>
>> I would be happy to drop this boilerplate, but how enum could help here?
>> To respond my requirement it should be something like set, not enum.
>> Even so, having set, I would have been needed to declare mapping between
>> names in set type and bit numbers within feature bitmask.
> 
> Instead of returning a bitmask ("mask":123) as well as an array naming
> those bits
> ([{"bit":1,"name":"bit1"},{"bit":2","name":"bit2"},{"bit":4,"name":"bit4},...]),
> you could omit the bit numbers and just return an array of named bits
> (["bit1", "bit2", "bit4"]).  An enum lets you declare up front what
> named bits are supported (and code can introspect when new named bits
> are supported in newer qemu).
>
But how can I declare in this notation that name "bit1" is owned by bit
#1, name "bit2" is owned by bit #2, name "bit4" is owned by bit #4, and
all other bits has no names.

> Perhaps it's easier to first take a step back, and show what the desired
> output might be like, and then we can figure out how to represent that
> output in QAPI.
> 

Yeah... I expect the following HMP output:

(qmue) info virtio
virtio-blk-device at 0000:00:07.0
  status:           0x07 acknowledge,driver,driver_ok
  host features:    0x0000000179000e54
  guest features:   0x0000000030000e54
  common features:
                   notify_on_empty
                        any_layout
                     indirect_desc                           acked
                         event_idx                           acked
                         version_1
  specific features:
                           seg_max                           acked
                          blk_size                           acked
                             flush                           acked
                          topology                           acked
virtio-serial-device at 0000:00:08.0
  status:           0x07 acknowledge,driver,driver_ok
  host features:    0x0000000179000006
  guest features:   0x0000000030000002
  common features:
                   notify_on_empty
                        any_layout
                     indirect_desc                           acked
                         event_idx                           acked
                         version_1
  specific features:
                         multiport                           acked
                       emerg_write
Markus Armbruster Oct. 6, 2017, 5:36 a.m. UTC | #7
Jan Dakinevich <jan.dakinevich@virtuozzo.com> writes:

> On 10/03/2017 05:02 PM, Eric Blake wrote:
>> On 10/03/2017 07:47 AM, Jan Dakinevich wrote:
>>> The command is intended for gathering virtio information such as status,
>>> feature bits, negotiation status. It is convenient and useful for debug
>>> purpose.
>>>
>>> The commands returns generic virtio information for virtio such as
>>> common feature names and status bits names and information for all
>>> attached to current machine devices.
>>>
>>> To retrieve names of device-specific features `get_feature_name'
>>> callback in VirtioDeviceClass also was introduced.
>>>
>>> Cc: Denis V. Lunev <den@virtuozzo.com>
>>> Signed-off-by: Jan Dakinevich <jan.dakinevich@virtuozzo.com>
>>> ---
>>>  hw/block/virtio-blk.c       |  21 +++++++++
>>>  hw/char/virtio-serial-bus.c |  15 +++++++
>>>  hw/display/virtio-gpu.c     |  13 ++++++
>>>  hw/net/virtio-net.c         |  35 +++++++++++++++
>>>  hw/scsi/virtio-scsi.c       |  16 +++++++
>>>  hw/virtio/Makefile.objs     |   2 +
>>>  hw/virtio/virtio-balloon.c  |  15 +++++++
>>>  hw/virtio/virtio-stub.c     |   9 ++++
>>>  hw/virtio/virtio.c          | 101 ++++++++++++++++++++++++++++++++++++++++++++
>>>  include/hw/virtio/virtio.h  |   2 +
>>>  qapi-schema.json            |   1 +
>>>  qapi/virtio.json            |  94 +++++++++++++++++++++++++++++++++++++++++
>>>  12 files changed, 324 insertions(+)
>>>  create mode 100644 hw/virtio/virtio-stub.c
>>>  create mode 100644 qapi/virtio.json
>> 
>> This creates a new .json file, but does not touch MAINTAINERS.  Our idea
>> in splitting the .json files was to make it easier for each sub-file
>> that needs a specific maintainer in addition to the overall *.json line
>> for QAPI maintainers, so this may deserve a MAINTAINERS entry.
>> 
>
> Ok.
>
>>> +++ b/qapi/virtio.json
>>> @@ -0,0 +1,94 @@
>>> +# -*- Mode: Python -*-
>>> +#
>>> +
>>> +##
>>> +# = Virtio devices
>>> +##
>>> +
>>> +{ 'include': 'common.json' }
>>> +
>>> +##
>>> +# @VirtioInfoBit:
>>> +#
>>> +# Named virtio bit
>>> +#
>>> +# @bit: bit number
>>> +#
>>> +# @name: bit name
>>> +#
>>> +# Since: 2.11.0
>>> +#
>>> +##
>>> +{
>>> +    'struct': 'VirtioInfoBit',
>>> +    'data': {
>>> +        'bit': 'uint64',
>> 
>> Why is this a 64-bit value? Are the values 0-63, or are they 1, 2, 4, 8,
>> ...?  The documentation on 'bit number' is rather sparse.
>
> I would prefer `uint' here, but I don't see generic unsigned type (may
> be, I am mistaken). I could use uint8 here, though.
>
>> 
>>> +        'name': 'str'
>> 
>> Wouldn't an enum type be better than an open-ended string?
>> 
>
> Bit names are not known here, they are obtained from virtio device
> implementations.

What exactly uses these bits?

Why do these uses justify pass-through?  By pass-through, I mean the
messenger (QEMU) merely passes them along, without understanding them.
Defeats introspection.

>>> +    }
>>> +}
>>> +
>>> +##
>>> +# @VirtioInfoDevice:
>>> +#
>>> +# Information about specific virtio device
>>> +#
>>> +# @qom_path: QOM path of the device
>> 
>> Please make this 'qom-path' - new interfaces should prefer '-' over '_'.
>
> Ok.
>
>>> +#
>>> +# @feature-names: names of device-specific features
>>> +#
>>> +# @host-features: bitmask of features, provided by devices
>>> +#
>>> +# @guest-features: bitmask of features, acknowledged by guest
>>> +#
>>> +# @status: virtio device status bitmask
>>> +#
>>> +# Since: 2.11.0
>>> +#
>>> +##
>>> +{
>>> +    'struct': 'VirtioInfoDevice',
>>> +    'data': {
>>> +        'qom_path': 'str',
>>> +        'feature-names': ['VirtioInfoBit'],
>>> +        'host-features': 'uint64',
>>> +        'guest-features': 'uint64',
>>> +        'status': 'uint64'
>> 
>> I'm wondering if this is the best representation (where the caller has
>> to parse the integer and then lookup in feature-names what each bit of
>> the integer represents).  But I'm not sure I have anything better off
>> the top of my head.
>> 
>
> Consider it as way to tell caller about names of supported features.

"Unsigned integer interpreted as combination of well-known bit-valued
symbols" is a fine C interface, but a pretty horrid QMP interface.
What's wrong with doing a set the straightforward way as "array of
enum"?

>>> +    }
>>> +}
>>> +
>>> +##
>>> +# @VirtioInfo:
>>> +#
>>> +# Information about virtio devices
>>> +#
>>> +# @feature-names: names of common virtio features
>>> +#
>>> +# @status-names: names of bits which represents virtio device status
>>> +#
>>> +# @devices: list of per-device virtio information
>>> +#
>>> +# Since: 2.11.0
>>> +#
>>> +##
>>> +{
>>> +    'struct': 'VirtioInfo',
>>> +    'data': {
>>> +        'feature-names': ['VirtioInfoBit'],
>> 
>> Why is feature-names listed at two different nestings of the return value?
>> 
>
> These are different feature names. First names are common and predefined
> for all devices. Second names are device-specific.
>
>>> +        'status-names': ['VirtioInfoBit'],
>>> +        'devices': ['VirtioInfoDevice']
>>> +    }
>>> +}
>>> +
>>> +
>>> +##
>>> +# @query-virtio:
>>> +#
>>> +# Returns generic and per-device virtio information
>>> +#
>>> +# Since: 2.11.0
>>> +#
>>> +##
>>> +{
>>> +    'command': 'query-virtio',
>>> +    'returns': 'VirtioInfo'
>>> +}
>>>
>>
Dr. David Alan Gilbert Oct. 6, 2017, 8:27 a.m. UTC | #8
* Markus Armbruster (armbru@redhat.com) wrote:
> Jan Dakinevich <jan.dakinevich@virtuozzo.com> writes:
> 
> > On 10/03/2017 05:02 PM, Eric Blake wrote:
> >> On 10/03/2017 07:47 AM, Jan Dakinevich wrote:
> >>> The command is intended for gathering virtio information such as status,
> >>> feature bits, negotiation status. It is convenient and useful for debug
> >>> purpose.
> >>>
> >>> The commands returns generic virtio information for virtio such as
> >>> common feature names and status bits names and information for all
> >>> attached to current machine devices.
> >>>
> >>> To retrieve names of device-specific features `get_feature_name'
> >>> callback in VirtioDeviceClass also was introduced.
> >>>
> >>> Cc: Denis V. Lunev <den@virtuozzo.com>
> >>> Signed-off-by: Jan Dakinevich <jan.dakinevich@virtuozzo.com>
> >>> ---
> >>>  hw/block/virtio-blk.c       |  21 +++++++++
> >>>  hw/char/virtio-serial-bus.c |  15 +++++++
> >>>  hw/display/virtio-gpu.c     |  13 ++++++
> >>>  hw/net/virtio-net.c         |  35 +++++++++++++++
> >>>  hw/scsi/virtio-scsi.c       |  16 +++++++
> >>>  hw/virtio/Makefile.objs     |   2 +
> >>>  hw/virtio/virtio-balloon.c  |  15 +++++++
> >>>  hw/virtio/virtio-stub.c     |   9 ++++
> >>>  hw/virtio/virtio.c          | 101 ++++++++++++++++++++++++++++++++++++++++++++
> >>>  include/hw/virtio/virtio.h  |   2 +
> >>>  qapi-schema.json            |   1 +
> >>>  qapi/virtio.json            |  94 +++++++++++++++++++++++++++++++++++++++++
> >>>  12 files changed, 324 insertions(+)
> >>>  create mode 100644 hw/virtio/virtio-stub.c
> >>>  create mode 100644 qapi/virtio.json
> >> 
> >> This creates a new .json file, but does not touch MAINTAINERS.  Our idea
> >> in splitting the .json files was to make it easier for each sub-file
> >> that needs a specific maintainer in addition to the overall *.json line
> >> for QAPI maintainers, so this may deserve a MAINTAINERS entry.
> >> 
> >
> > Ok.
> >
> >>> +++ b/qapi/virtio.json
> >>> @@ -0,0 +1,94 @@
> >>> +# -*- Mode: Python -*-
> >>> +#
> >>> +
> >>> +##
> >>> +# = Virtio devices
> >>> +##
> >>> +
> >>> +{ 'include': 'common.json' }
> >>> +
> >>> +##
> >>> +# @VirtioInfoBit:
> >>> +#
> >>> +# Named virtio bit
> >>> +#
> >>> +# @bit: bit number
> >>> +#
> >>> +# @name: bit name
> >>> +#
> >>> +# Since: 2.11.0
> >>> +#
> >>> +##
> >>> +{
> >>> +    'struct': 'VirtioInfoBit',
> >>> +    'data': {
> >>> +        'bit': 'uint64',
> >> 
> >> Why is this a 64-bit value? Are the values 0-63, or are they 1, 2, 4, 8,
> >> ...?  The documentation on 'bit number' is rather sparse.
> >
> > I would prefer `uint' here, but I don't see generic unsigned type (may
> > be, I am mistaken). I could use uint8 here, though.
> >
> >> 
> >>> +        'name': 'str'
> >> 
> >> Wouldn't an enum type be better than an open-ended string?
> >> 
> >
> > Bit names are not known here, they are obtained from virtio device
> > implementations.
> 
> What exactly uses these bits?
> 
> Why do these uses justify pass-through?  By pass-through, I mean the
> messenger (QEMU) merely passes them along, without understanding them.
> Defeats introspection.

It should be noted originally it was HMP - this was just a debug command
and it's only getting the need to be introspectable because people
insisted it had a QMP version.

I think the intent is to print all flags, even ones we dont yet
understand.

Dave

> >>> +    }
> >>> +}
> >>> +
> >>> +##
> >>> +# @VirtioInfoDevice:
> >>> +#
> >>> +# Information about specific virtio device
> >>> +#
> >>> +# @qom_path: QOM path of the device
> >> 
> >> Please make this 'qom-path' - new interfaces should prefer '-' over '_'.
> >
> > Ok.
> >
> >>> +#
> >>> +# @feature-names: names of device-specific features
> >>> +#
> >>> +# @host-features: bitmask of features, provided by devices
> >>> +#
> >>> +# @guest-features: bitmask of features, acknowledged by guest
> >>> +#
> >>> +# @status: virtio device status bitmask
> >>> +#
> >>> +# Since: 2.11.0
> >>> +#
> >>> +##
> >>> +{
> >>> +    'struct': 'VirtioInfoDevice',
> >>> +    'data': {
> >>> +        'qom_path': 'str',
> >>> +        'feature-names': ['VirtioInfoBit'],
> >>> +        'host-features': 'uint64',
> >>> +        'guest-features': 'uint64',
> >>> +        'status': 'uint64'
> >> 
> >> I'm wondering if this is the best representation (where the caller has
> >> to parse the integer and then lookup in feature-names what each bit of
> >> the integer represents).  But I'm not sure I have anything better off
> >> the top of my head.
> >> 
> >
> > Consider it as way to tell caller about names of supported features.
> 
> "Unsigned integer interpreted as combination of well-known bit-valued
> symbols" is a fine C interface, but a pretty horrid QMP interface.
> What's wrong with doing a set the straightforward way as "array of
> enum"?
> 
> >>> +    }
> >>> +}
> >>> +
> >>> +##
> >>> +# @VirtioInfo:
> >>> +#
> >>> +# Information about virtio devices
> >>> +#
> >>> +# @feature-names: names of common virtio features
> >>> +#
> >>> +# @status-names: names of bits which represents virtio device status
> >>> +#
> >>> +# @devices: list of per-device virtio information
> >>> +#
> >>> +# Since: 2.11.0
> >>> +#
> >>> +##
> >>> +{
> >>> +    'struct': 'VirtioInfo',
> >>> +    'data': {
> >>> +        'feature-names': ['VirtioInfoBit'],
> >> 
> >> Why is feature-names listed at two different nestings of the return value?
> >> 
> >
> > These are different feature names. First names are common and predefined
> > for all devices. Second names are device-specific.
> >
> >>> +        'status-names': ['VirtioInfoBit'],
> >>> +        'devices': ['VirtioInfoDevice']
> >>> +    }
> >>> +}
> >>> +
> >>> +
> >>> +##
> >>> +# @query-virtio:
> >>> +#
> >>> +# Returns generic and per-device virtio information
> >>> +#
> >>> +# Since: 2.11.0
> >>> +#
> >>> +##
> >>> +{
> >>> +    'command': 'query-virtio',
> >>> +    'returns': 'VirtioInfo'
> >>> +}
> >>>
> >> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
diff mbox series

Patch

diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 05d1440..c77f651 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -1017,6 +1017,26 @@  static Property virtio_blk_properties[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
+static const char *virtio_blk_get_feature_name(VirtIODevice *vdev,
+                                               unsigned feature)
+{
+    static const char *names[] = {
+        [VIRTIO_BLK_F_BARRIER] = "barrier",
+        [VIRTIO_BLK_F_SIZE_MAX] = "size_max",
+        [VIRTIO_BLK_F_SEG_MAX] = "seg_max",
+        [VIRTIO_BLK_F_RO] = "ro",
+        [VIRTIO_BLK_F_BLK_SIZE] = "blk_size",
+        [VIRTIO_BLK_F_SCSI] = "scsi",
+        [VIRTIO_BLK_F_TOPOLOGY] = "topology",
+        [VIRTIO_BLK_F_FLUSH] = "flush",
+        [VIRTIO_BLK_F_MQ] = "mq",
+    };
+    if (feature >= ARRAY_SIZE(names)) {
+        return NULL;
+    }
+    return names[feature];
+}
+
 static void virtio_blk_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -1030,6 +1050,7 @@  static void virtio_blk_class_init(ObjectClass *klass, void *data)
     vdc->get_config = virtio_blk_update_config;
     vdc->set_config = virtio_blk_set_config;
     vdc->get_features = virtio_blk_get_features;
+    vdc->get_feature_name = virtio_blk_get_feature_name;
     vdc->set_status = virtio_blk_set_status;
     vdc->reset = virtio_blk_reset;
     vdc->save = virtio_blk_save_device;
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
index 9470bd7..41f4466 100644
--- a/hw/char/virtio-serial-bus.c
+++ b/hw/char/virtio-serial-bus.c
@@ -1156,6 +1156,20 @@  static Property virtio_serial_properties[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
+static const char *virtio_serial_get_feature_name(VirtIODevice *vdev,
+                                                  unsigned feature)
+{
+    static const char *names[] = {
+        [VIRTIO_CONSOLE_F_SIZE] = "size",
+        [VIRTIO_CONSOLE_F_MULTIPORT] = "multiport",
+        [VIRTIO_CONSOLE_F_EMERG_WRITE] = "emerg_write",
+    };
+    if (feature >= ARRAY_SIZE(names)) {
+        return NULL;
+    }
+    return names[feature];
+}
+
 static void virtio_serial_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -1170,6 +1184,7 @@  static void virtio_serial_class_init(ObjectClass *klass, void *data)
     vdc->realize = virtio_serial_device_realize;
     vdc->unrealize = virtio_serial_device_unrealize;
     vdc->get_features = get_features;
+    vdc->get_feature_name = virtio_serial_get_feature_name;
     vdc->get_config = get_config;
     vdc->set_config = set_config;
     vdc->set_status = set_status;
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 3a8f1e1..49aa214 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -1307,6 +1307,18 @@  static Property virtio_gpu_properties[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
+static const char *virtio_gpu_get_feature_name(VirtIODevice *vdev,
+                                               unsigned feature)
+{
+    static const char *names[] = {
+        [VIRTIO_GPU_F_VIRGL] = "virgl",
+    };
+    if (feature >= ARRAY_SIZE(names)) {
+        return NULL;
+    }
+    return names[feature];
+}
+
 static void virtio_gpu_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -1317,6 +1329,7 @@  static void virtio_gpu_class_init(ObjectClass *klass, void *data)
     vdc->get_config = virtio_gpu_get_config;
     vdc->set_config = virtio_gpu_set_config;
     vdc->get_features = virtio_gpu_get_features;
+    vdc->get_feature_name = virtio_gpu_get_feature_name;
     vdc->set_features = virtio_gpu_set_features;
 
     vdc->reset = virtio_gpu_reset;
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 148071a..f4d20a85 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -2154,6 +2154,40 @@  static Property virtio_net_properties[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
+static const char *virtio_net_get_feature_name(VirtIODevice *vdev,
+                                               unsigned feature)
+{
+    static const char *names[] = {
+        [VIRTIO_NET_F_CSUM] = "csum",
+        [VIRTIO_NET_F_GUEST_CSUM] = "guest_csum",
+        [VIRTIO_NET_F_CTRL_GUEST_OFFLOADS] = "ctrl_guest_offloads",
+        [VIRTIO_NET_F_MTU] = "mtu",
+        [VIRTIO_NET_F_MAC] = "mac",
+        [VIRTIO_NET_F_GSO] = "gso",
+        [VIRTIO_NET_F_GUEST_TSO4] = "guest_tso4",
+        [VIRTIO_NET_F_GUEST_TSO6] = "guest_tso6",
+        [VIRTIO_NET_F_GUEST_ECN] = "guest_ecn",
+        [VIRTIO_NET_F_GUEST_UFO] = "guest_ufo",
+        [VIRTIO_NET_F_HOST_TSO4] = "host_tso4",
+        [VIRTIO_NET_F_HOST_TSO6] = "host_tso6",
+        [VIRTIO_NET_F_HOST_ECN] = "host_ecn",
+        [VIRTIO_NET_F_HOST_UFO] = "host_ufo",
+        [VIRTIO_NET_F_MRG_RXBUF] = "mrg_rxbuf",
+        [VIRTIO_NET_F_STATUS] = "status",
+        [VIRTIO_NET_F_CTRL_VQ] = "ctrl_vq",
+        [VIRTIO_NET_F_CTRL_RX] = "ctrl_rx",
+        [VIRTIO_NET_F_CTRL_VLAN] = "ctrl_vlan",
+        [VIRTIO_NET_F_CTRL_RX_EXTRA] = "ctrl_rx_extra",
+        [VIRTIO_NET_F_GUEST_ANNOUNCE] = "guest_announce",
+        [VIRTIO_NET_F_MQ] = "mq",
+        [VIRTIO_NET_F_CTRL_MAC_ADDR] = "ctrl_mac_addr",
+    };
+    if (feature >= ARRAY_SIZE(names)) {
+        return NULL;
+    }
+    return names[feature];
+}
+
 static void virtio_net_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -2169,6 +2203,7 @@  static void virtio_net_class_init(ObjectClass *klass, void *data)
     vdc->get_features = virtio_net_get_features;
     vdc->set_features = virtio_net_set_features;
     vdc->bad_features = virtio_net_bad_features;
+    vdc->get_feature_name = virtio_net_get_feature_name;
     vdc->reset = virtio_net_reset;
     vdc->set_status = virtio_net_set_status;
     vdc->guest_notifier_mask = virtio_net_guest_notifier_mask;
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index 3aa9971..b53cf8b 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -942,6 +942,21 @@  static const VMStateDescription vmstate_virtio_scsi = {
     },
 };
 
+static const char *virtio_scsi_get_feature_name(VirtIODevice *vdev,
+                                                unsigned feature)
+{
+    static const char *names[] = {
+        [VIRTIO_SCSI_F_INOUT] = "inout",
+        [VIRTIO_SCSI_F_HOTPLUG] = "hotplug",
+        [VIRTIO_SCSI_F_CHANGE] = "change",
+        [VIRTIO_SCSI_F_T10_PI] = "t10_pi",
+    };
+    if (feature >= ARRAY_SIZE(names)) {
+        return NULL;
+    }
+    return names[feature];
+}
+
 static void virtio_scsi_common_class_init(ObjectClass *klass, void *data)
 {
     VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
@@ -964,6 +979,7 @@  static void virtio_scsi_class_init(ObjectClass *klass, void *data)
     vdc->unrealize = virtio_scsi_device_unrealize;
     vdc->set_config = virtio_scsi_set_config;
     vdc->get_features = virtio_scsi_get_features;
+    vdc->get_feature_name = virtio_scsi_get_feature_name;
     vdc->reset = virtio_scsi_reset;
     vdc->start_ioeventfd = virtio_scsi_dataplane_start;
     vdc->stop_ioeventfd = virtio_scsi_dataplane_stop;
diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs
index 765d363..73f3527 100644
--- a/hw/virtio/Makefile.objs
+++ b/hw/virtio/Makefile.objs
@@ -9,6 +9,8 @@  obj-$(CONFIG_LINUX) += vhost.o vhost-backend.o vhost-user.o
 obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock.o
 obj-y += virtio-crypto.o
 obj-$(CONFIG_VIRTIO_PCI) += virtio-crypto-pci.o
+else
+obj-y += virtio-stub.o
 endif
 
 common-obj-$(call lnot,$(CONFIG_LINUX)) += vhost-stub.o
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index 37cde38..b396eb1 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -509,6 +509,20 @@  static Property virtio_balloon_properties[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
+static const char *virtio_balloon_get_feature_name(VirtIODevice *vdev,
+                                                   unsigned feature)
+{
+    static const char *names[] = {
+        [VIRTIO_BALLOON_F_MUST_TELL_HOST] = "must_tell_host",
+        [VIRTIO_BALLOON_F_STATS_VQ] = "stats_vq",
+        [VIRTIO_BALLOON_F_DEFLATE_ON_OOM] = "deflate_on_oom",
+    };
+    if (feature >= ARRAY_SIZE(names)) {
+        return NULL;
+    }
+    return names[feature];
+}
+
 static void virtio_balloon_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -523,6 +537,7 @@  static void virtio_balloon_class_init(ObjectClass *klass, void *data)
     vdc->get_config = virtio_balloon_get_config;
     vdc->set_config = virtio_balloon_set_config;
     vdc->get_features = virtio_balloon_get_features;
+    vdc->get_feature_name = virtio_balloon_get_feature_name;
     vdc->set_status = virtio_balloon_set_status;
     vdc->vmsd = &vmstate_virtio_balloon_device;
 }
diff --git a/hw/virtio/virtio-stub.c b/hw/virtio/virtio-stub.c
new file mode 100644
index 0000000..51a99de
--- /dev/null
+++ b/hw/virtio/virtio-stub.c
@@ -0,0 +1,9 @@ 
+#include "qemu/osdep.h"
+#include "qmp-commands.h"
+#include "qapi/qmp/qerror.h"
+
+VirtioInfo *qmp_query_virtio(Error **errp)
+{
+    error_setg(errp, QERR_UNSUPPORTED);
+    return NULL;
+}
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 3129d25..f182aa7 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -13,6 +13,7 @@ 
 
 #include "qemu/osdep.h"
 #include "qapi/error.h"
+#include "qmp-commands.h"
 #include "qemu-common.h"
 #include "cpu.h"
 #include "trace.h"
@@ -2665,6 +2666,106 @@  bool virtio_device_ioeventfd_enabled(VirtIODevice *vdev)
     return virtio_bus_ioeventfd_enabled(vbus);
 }
 
+static void virtio_info_bit_list_add(VirtioInfoBitList **list, unsigned bit,
+    const char *name)
+{
+    VirtioInfoBitList *info = g_new0(VirtioInfoBitList, 1);
+
+    info->next = *list;
+    *list = info;
+
+    info->value = g_new0(VirtioInfoBit, 1);
+    info->value->bit = bit;
+    info->value->name = g_strdup(name);
+}
+
+static void virtio_info_device_list_add(VirtioInfoDeviceList **list,
+                                        VirtIODevice *vdev)
+{
+    VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
+    VirtioInfoDeviceList *device;
+    unsigned idx;
+
+    device = g_new0(VirtioInfoDeviceList, 1);
+    device->value = g_new0(VirtioInfoDevice, 1);
+    device->next = *list;
+
+    *list = device;
+
+    device->value->qom_path = object_get_canonical_path(OBJECT(vdev));
+    device->value->host_features = vdev->host_features;
+    device->value->guest_features = vdev->guest_features;
+    device->value->status = vdev->status;
+
+    if (!vdc->get_feature_name) {
+        return;
+    }
+
+    for (idx = 64; idx--; ) {
+        const char *name = vdc->get_feature_name(vdev, idx);
+        if (!name) {
+            continue;
+        }
+        virtio_info_bit_list_add(&device->value->feature_names, idx, name);
+    }
+}
+
+static void qmp_query_virtio_recursive(VirtioInfo *info, BusState *bus)
+{
+    BusChild *kid;
+
+    QTAILQ_FOREACH(kid, &bus->children, sibling) {
+        DeviceState *dev = kid->child;
+        BusState *child;
+
+        if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_DEVICE)) {
+            virtio_info_device_list_add(&info->devices, VIRTIO_DEVICE(dev));
+        }
+        QLIST_FOREACH(child, &dev->child_bus, sibling) {
+            qmp_query_virtio_recursive(info, child);
+        }
+    }
+}
+
+VirtioInfo *qmp_query_virtio(Error **errp)
+{
+    BusState *bus = sysbus_get_default();
+    VirtioInfo *info = g_new0(VirtioInfo, 1);
+
+    /* Common features */
+    virtio_info_bit_list_add(&info->feature_names, VIRTIO_F_IOMMU_PLATFORM,
+                             "iommu_platform");
+    virtio_info_bit_list_add(&info->feature_names, VIRTIO_F_VERSION_1,
+                             "version_1");
+    virtio_info_bit_list_add(&info->feature_names, VIRTIO_RING_F_EVENT_IDX,
+                             "event_idx");
+    virtio_info_bit_list_add(&info->feature_names, VIRTIO_RING_F_INDIRECT_DESC,
+                             "indirect_desc");
+    virtio_info_bit_list_add(&info->feature_names, VIRTIO_F_ANY_LAYOUT,
+                             "any_layout");
+    virtio_info_bit_list_add(&info->feature_names, VIRTIO_F_NOTIFY_ON_EMPTY,
+                             "notify_on_empty");
+
+    /* Status bits */
+    virtio_info_bit_list_add(&info->status_names, 7 /* VIRTIO_CONFIG_S_FAILED */,
+                             "failed");
+    virtio_info_bit_list_add(&info->status_names, 6 /* VIRTIO_CONFIG_S_NEEDS_RESET */,
+                             "needs_reset");
+    virtio_info_bit_list_add(&info->status_names, 3 /* VIRTIO_CONFIG_S_FEATURES_OK */,
+                             "features_ok");
+    virtio_info_bit_list_add(&info->status_names, 2 /* VIRTIO_CONFIG_S_DRIVER_OK */,
+                             "driver_ok");
+    virtio_info_bit_list_add(&info->status_names, 1 /* VIRTIO_CONFIG_S_DRIVER */,
+                             "driver");
+    virtio_info_bit_list_add(&info->status_names, 0 /* VIRTIO_CONFIG_S_ACKNOWLEDGE */,
+                             "acknowledge");
+
+    if (bus) {
+        qmp_query_virtio_recursive(info, bus);
+    }
+    return info;
+}
+
 static const TypeInfo virtio_device_info = {
     .name = TYPE_VIRTIO_DEVICE,
     .parent = TYPE_DEVICE,
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index 80c45c3..3ea2cd0 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -141,6 +141,8 @@  typedef struct VirtioDeviceClass {
     void (*save)(VirtIODevice *vdev, QEMUFile *f);
     int (*load)(VirtIODevice *vdev, QEMUFile *f, int version_id);
     const VMStateDescription *vmsd;
+    /* Get the name of device specific feature */
+    const char *(*get_feature_name)(VirtIODevice *vdev, unsigned feature);
 } VirtioDeviceClass;
 
 void virtio_instance_init_common(Object *proxy_obj, void *data,
diff --git a/qapi-schema.json b/qapi-schema.json
index a3ba1c9..78762b1 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -92,6 +92,7 @@ 
 { 'include': 'qapi/transaction.json' }
 { 'include': 'qapi/trace.json' }
 { 'include': 'qapi/introspect.json' }
+{ 'include': 'qapi/virtio.json' }
 
 ##
 # = Miscellanea
diff --git a/qapi/virtio.json b/qapi/virtio.json
new file mode 100644
index 0000000..b8b52ac
--- /dev/null
+++ b/qapi/virtio.json
@@ -0,0 +1,94 @@ 
+# -*- Mode: Python -*-
+#
+
+##
+# = Virtio devices
+##
+
+{ 'include': 'common.json' }
+
+##
+# @VirtioInfoBit:
+#
+# Named virtio bit
+#
+# @bit: bit number
+#
+# @name: bit name
+#
+# Since: 2.11.0
+#
+##
+{
+    'struct': 'VirtioInfoBit',
+    'data': {
+        'bit': 'uint64',
+        'name': 'str'
+    }
+}
+
+##
+# @VirtioInfoDevice:
+#
+# Information about specific virtio device
+#
+# @qom_path: QOM path of the device
+#
+# @feature-names: names of device-specific features
+#
+# @host-features: bitmask of features, provided by devices
+#
+# @guest-features: bitmask of features, acknowledged by guest
+#
+# @status: virtio device status bitmask
+#
+# Since: 2.11.0
+#
+##
+{
+    'struct': 'VirtioInfoDevice',
+    'data': {
+        'qom_path': 'str',
+        'feature-names': ['VirtioInfoBit'],
+        'host-features': 'uint64',
+        'guest-features': 'uint64',
+        'status': 'uint64'
+    }
+}
+
+##
+# @VirtioInfo:
+#
+# Information about virtio devices
+#
+# @feature-names: names of common virtio features
+#
+# @status-names: names of bits which represents virtio device status
+#
+# @devices: list of per-device virtio information
+#
+# Since: 2.11.0
+#
+##
+{
+    'struct': 'VirtioInfo',
+    'data': {
+        'feature-names': ['VirtioInfoBit'],
+        'status-names': ['VirtioInfoBit'],
+        'devices': ['VirtioInfoDevice']
+    }
+}
+
+
+##
+# @query-virtio:
+#
+# Returns generic and per-device virtio information
+#
+# Since: 2.11.0
+#
+##
+{
+    'command': 'query-virtio',
+    'returns': 'VirtioInfo'
+}