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' +} + +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