On Thu, May 06, 2021 at 09:33:41PM +0200, Laurent Vivier wrote: > Add "lsvirtio" that lists all virtio devices in a system > the same way lspci does for the PCI cards. > > For instance: > > $ ./lsvirtio > 0000:01:00.0 virtio0 Red Hat, Inc. (PCI) Virtio Network Card > Subsystem: virtio > Modalias: virtio:d00000001v00001AF4 > Status: ACKNOWLEDGE DRIVER_OK DRIVER FEATURES_OK > Feature: CSUM > Feature: GUEST_CSUM > Feature: CTRL_GUEST_OFFLOADS > Feature: MAC > Feature: GUEST_TSO4 > Feature: GUEST_TSO6 > Feature: GUEST_ECN > Feature: GUEST_UFO > Feature: HOST_TSO4 > Feature: HOST_TSO6 > Feature: HOST_ECN > Feature: HOST_UFO > Feature: MRG_RXBUF > Feature: STATUS > Feature: CTRL_VQ > Feature: CTRL_RX > Feature: CTRL_VLAN > Feature: GUEST_ANNOUNCE > Feature: CTRL_MAC_ADDR > Feature: RING_INDIRECT_DESC > Feature: RING_EVENT_IDX > Feature: VERSION_1 > Kernel driver in use: virtio_net > Interfaces: enp1s0 > > 0000:03:00.0 virtio1 Red Hat, Inc. (PCI) Virtio Console > Subsystem: virtio > Modalias: virtio:d00000003v00001AF4 > Status: ACKNOWLEDGE DRIVER_OK DRIVER FEATURES_OK > Feature: MULTIPORT > Feature: RING_INDIRECT_DESC > Feature: RING_EVENT_IDX > Feature: VERSION_1 > Kernel driver in use: virtio_console > Interfaces: vport1p1 > ... > > This is useful to have the list of virtio devices when they are not > mapped by a PCI card: > > $ ./lsvirtio > virtio-mmio.121 virtio0 Virt (MMIO) Virtio 9P transport > Subsystem: virtio > Modalias: virtio:d00000009v554D4551 > Status: FEATURES_OK ACKNOWLEDGE DRIVER DRIVER_OK > Feature: MOUNT_TAG > Feature: RING_INDIRECT_DESC > Feature: RING_EVENT_IDX > Feature: VERSION_1 > Kernel driver in use: 9pnet_virtio > Interfaces: home0 > > virtio-mmio.122 virtio1 Virt (MMIO) Virtio GPU Device > Subsystem: virtio > Modalias: virtio:d00000010v554D4551 > Status: FEATURES_OK ACKNOWLEDGE DRIVER DRIVER_OK > Feature: EDID > Feature: RING_INDIRECT_DESC > Feature: RING_EVENT_IDX > Feature: VERSION_1 > Kernel driver in use: virtio_gpu > Interfaces: fb0 > ... > > Signed-off-by: Laurent Vivier <lviv...@redhat.com> > --- > scripts/lsvirtio | 317 +++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 317 insertions(+) > create mode 100755 scripts/lsvirtio > > diff --git a/scripts/lsvirtio b/scripts/lsvirtio > new file mode 100755 > index 000000000000..f457d5b7344d > --- /dev/null > +++ b/scripts/lsvirtio > @@ -0,0 +1,317 @@ > +#!/usr/bin/env python3 > +# > +# Copyright (C) 2021 Red Hat, Inc. > +# > +# SPDX-License-Identifier: GPL-2.0-or-later > + > +import os > + > +# Virtual I/O Device (VIRTIO) Version 1.1 > + > +# 2.1 Device Status Field > +status_name = { > + ( 1, 'ACKNOWLEDGE' ), > + ( 2, 'DRIVER') , > + ( 4, 'DRIVER_OK' ), > + ( 8, 'FEATURES_OK' ), > + ( 64, 'DEVICE_NEEDS_RESET' ), > + ( 128, 'FAILED' ) > +} > + > +# 5 Device Types > +device_name = { > + 1:'Network Card', > + 2:'Block Device', > + 3:'Console', > + 4:'Entropy Source', > + 5:'Memory Ballooning (traditional)', > + 6:'ioMemory', > + 7:'rpmsg', > + 8:'SCSI host', > + 9:'9P transport', > + 10:'MAC80211 WLAN', > + 11:'rproc serial', > + 12:'CAIF', > + 13:'Memory Balloon', > + 16:'GPU Device', > + 17:'Timer/Clock Device', > + 18:'Input Device', > + 19:'Socket Device', > + 20:'Crypto Device', > + 21:'Signal Distribution Module', > + 22:'pstore Device', > + 23:'IOMMU Device', > + 24:'Memory Device', > +# From linux headers > + 26:'Filesystem', > + 27:'pmem', > + 29:'mac80211-hwsim', > +} > + > +# 5.1 Network Device > +# 5.1.3 Feature bits > +net_feature_name = { > + 0:'CSUM', > + 1:'GUEST_CSUM', > + 2:'CTRL_GUEST_OFFLOADS', > + 3:'MTU', > + 5:'MAC', > + 6:'GSO', > + 7:'GUEST_TSO4', > + 8:'GUEST_TSO6', > + 9:'GUEST_ECN', > + 10:'GUEST_UFO', > + 11:'HOST_TSO4', > + 12:'HOST_TSO6', > + 13:'HOST_ECN', > + 14:'HOST_UFO', > + 15:'MRG_RXBUF', > + 16:'STATUS', > + 17:'CTRL_VQ', > + 18:'CTRL_RX', > + 19:'CTRL_VLAN', > + 21:'GUEST_ANNOUNCE', > + 22:'MQ', > + 23:'CTRL_MAC_ADDR', > + 41:'GUEST_RSC4', > + 42:'GUEST_RSC6', > + 61:'RSC_EXT', > + 62:'STANDBY', > +} > + > +def get_feature_net(feature): > + return net_feature_name[feature] > + > +# 5.2 Block Device > +# 5.2.3 Feature bits > +block_feature_name = { > + 0:'BARRIER', > + 1:'SIZE_MAX', > + 2:'SEG_MAX', > + 4:'GEOMETRY', > + 5:'RO', > + 6:'BLK_SIZE', > + 7:'SCSI', > + 9:'FLUSH', > + 10:'TOPOLOGY', > + 11:'CONFIG_WCE', > + 13:'DISCARD', > + 14:'WRITE_ZEROES', > +} > + > +def get_feature_block(feature): > + return block_feature_name[feature] > + > +# 5.3 Console Device > +# 5.3.3 Feature bits > +console_feature_name = { > + 0:'SIZE', > + 1:'MULTIPORT', > + 2:'EMERG_WRITE', > +} > + > +def get_feature_console(feature): > + return console_feature_name[feature] > + > +# 5.4 Entropy Device > +# 5.4.3 Feature bits > +# No feature bits > + > +# 5.5 Traditional Memory Balloon Device > +# 5.5.3 Feature bits > +balloon_traditional_feature_name = { > + 0:'MUST_TELL_HOST', > + 1:'STATS_VQ', > + 2:'DEFLATE_ON_OOM', > +# from linux headers > + 3:'FREE_PAGE_HINT', > + 4:'PAGE_POISON', > + 5:'REPORTING', > +} > + > +def get_feature_balloon_traditional(feature): > + return balloon_traditional_feature_name[feature] > + > +# 5.6 SCSI Host Device > +# 5.6.3 Feature bits > +scsi_feature_name = { > + 0:'INOUT', > + 1:'HOTPLUG', > + 2:'CHANGE', > + 3:'T10_PI', > +} > + > +def get_feature_scsi_host(feature): > + return scsi_feature_name[feature] > + > +# 5.7 GPU Device > +# 5.7.3 Feature bits > +gpu_feature_name = { > + 0:'VIRGL', > + 1:'EDID', > +} > + > +def get_feature_gpu(feature): > + return gpu_feature_name[feature] > + > +# 5.8 Input Device > +# 5.8.3 Feature bits > +# No feature bits > + > +# 5.9 Crypto Device > +# 5.9.3 Feature bits > +crypto_feature_name = { > + 0:'REVISION_1', > + 1:'CIPHER_STATELESS_MODE', > + 2:'HASH_STATELESS_MODE', > + 3:'MAC_STATELESS_MODE', > + 4:'AEAD_STATELESS_MODE', > +} > + > +def get_feature_crypto(feature): > + return crypto_feature_name[feature] > + > +# 5.10 Socket Device > +# 5.10.3 Feature bits > +# No feature bits > + > +# following feature bits from linux headers > +# 9P > +ninep_feature_name = { > + 0:'MOUNT_TAG', > +} > + > +def get_feature_9p(feature): > + return ninep_feature_name[feature] > + > +# IOMMU > +iommu_feature_name = { > + 0:'INPUT_RANGE', > + 1:'DOMAIN_RANGE', > + 2:'MAP_UNMAP', > + 3:'BYPASS', > + 4:'PROBE', > + 5:'MMIO', > +} > + > +def get_feature_iommu(feature): > + return iommu_feature_name[feature] > + > +# MEM > + > +mem_feature_name = { > + 0:'ACPI_PXM', > +} > + > +def get_feature_memory(feature): > + return mem_feature_name[feature] > + > +get_feature = { > + 1:get_feature_net, > + 2:get_feature_block, > + 3:get_feature_console, > + 5:get_feature_balloon_traditional, > + 8:get_feature_scsi_host, > + 9:get_feature_9p, > + 16:get_feature_gpu, > + 20:get_feature_crypto, > + 23:get_feature_iommu, > + 24:get_feature_memory, > +} > + > +# 6 Reserved Feature Bits > +reserved_feature_name = { > + 24:'NOTIFY_ON_EMPTY', > + 27:'ANY_LAYOUT', > + 28:'RING_INDIRECT_DESC', > + 29:'RING_EVENT_IDX', > + 30:'BAD_FEATURE', > + 32:'VERSION_1', > + 33:'ACCESS_PLATFORM', > + 34:'RING_PACKED', > + 35:'IN_ORDER', > + 36:'ORDER_PLATFORM', > + 37:'SR_IOV', > + 38:'NOTIFICATION_DATA' > +}
I worry about maintaining all these feature bits though. Can we somehow script this in scripts/update-linux-headers.sh ? > + > +vendor_name = { > + 0x554D4551:'Virt (MMIO)', > + 0x1AF4:'Red Hat, Inc. (PCI)', > +} > + > +def get_status_name(status): > + result = '' > + for name in status_name: > + if name[0] & status: > + result = result + name[1] + ' ' > + return result > + > +def list_interfaces(path): > + interfaces = '' > + for interface in sorted(os.listdir(path)): > + interfaces = interfaces + interface + ' ' > + return interfaces > + > +def get_net_interfaces(path): > + return list_interfaces(path + '/net') > + > +def get_block_interfaces(path): > + return list_interfaces(path + '/block') > + > +def get_console_interfaces(path): > + return list_interfaces(path + '/block') > + > +def get_9p_interfaces(path): > + return open(path + '/mount_tag').read().rstrip() > + > +def get_gpu_interfaces(path): > + return list_interfaces(path + '/graphics') > + > +def get_input_interaces(path): > + return list_interfaces(path + '/input') > + > +get_interfaces = { > + 1:get_net_interfaces, > + 2:get_block_interfaces, > + 3:get_console_interfaces, > + 9:get_9p_interfaces, > + 16:get_gpu_interfaces, > + 18:get_input_interaces, > +} > + > +busses = '/sys/bus/virtio' > +devices = busses + '/devices' > + > +for device in sorted(os.listdir(devices)): > + bus = os.path.basename(os.path.dirname(os.readlink(devices + '/' + > device))) > + path = devices + '/' + device > + subsystem = os.path.basename(os.readlink(path + '/subsystem')) > + device_id = int(open(path + '/device').read(), base = 0) > + vendor = int(open(path + '/vendor').read(), base = 0) > + driver = os.path.basename(os.readlink(path + '/driver')) > + modalias = open(path + '/modalias').read().rstrip() > + features = open(path + '/features').read().rstrip() > + status = open(path + '/status').read().rstrip() > + > + print(bus + ' ' + device + ' ' + vendor_name[vendor] + ' Virtio ' + > device_name[device_id]) > + print('\tSubsystem: ' + subsystem) > + print('\tModalias: ' + modalias) > + print('\tStatus: ' + get_status_name(int(status, base=0))) > + bit=0 > + for feature in features: > + if feature == '1': > + try: > + if bit >= 24: > + print('\tFeature: ' + reserved_feature_name[bit]) > + else: > + print('\tFeature: ' + get_feature[device_id](bit)) > + except: > + print('\tFeature: ' + str(bit)) > + bit += 1 > + print('\tKernel driver in use: ' + driver) > + try: > + print('\tInterfaces: ' + get_interfaces[device_id](path)) > + except: > + print('\tNo interface') > + print('') > -- > 2.31.1 > >