@@ -877,3 +877,221 @@ SRST
``info sgx``
Show intel SGX information.
ERST
+
+ {
+ .name = "virtio",
+ .args_type = "",
+ .params = "",
+ .help = "List all available virtio devices",
+ .cmd = hmp_virtio_query,
+ .flags = "p",
+ },
+
+SRST
+ ``info virtio``
+ List all available virtio devices
+
+ Example:
+
+ List all available virtio devices in the machine::
+
+ (qemu) info virtio
+ /machine/peripheral/vsock0/virtio-backend [vhost-vsock]
+ /machine/peripheral/crypto0/virtio-backend [virtio-crypto]
+ /machine/peripheral-anon/device[2]/virtio-backend [virtio-scsi]
+ /machine/peripheral-anon/device[1]/virtio-backend [virtio-net]
+ /machine/peripheral-anon/device[0]/virtio-backend [virtio-serial]
+
+ERST
+
+ {
+ .name = "virtio-status",
+ .args_type = "path:s",
+ .params = "path",
+ .help = "Display status of a given virtio device",
+ .cmd = hmp_virtio_status,
+ .flags = "p",
+ },
+
+SRST
+ ``info virtio-status`` *path*
+ Display status of a given virtio device
+
+ Example:
+
+ Dump the status of virtio-net (vhost on)::
+
+ (qemu) info virtio-status /machine/peripheral-anon/device[1]/virtio-backend
+ /machine/peripheral-anon/device[1]/virtio-backend:
+ device_name: virtio-net (vhost)
+ device_id: 1
+ vhost_started: true
+ bus_name: (null)
+ broken: false
+ disabled: false
+ disable_legacy_check: false
+ started: true
+ use_started: true
+ start_on_kick: false
+ use_guest_notifier_mask: true
+ vm_running: true
+ num_vqs: 3
+ queue_sel: 2
+ isr: 1
+ endianness: little
+ status: acknowledge, driver, features-ok, driver-ok
+ Guest features: event-idx, indirect-desc, version-1
+ ctrl-mac-addr, guest-announce, ctrl-vlan, ctrl-rx, ctrl-vq, status, mrg-rxbuf,
+ host-ufo, host-ecn, host-tso6, host-tso4, guest-ufo, guest-ecn, guest-tso6,
+ guest-tso4, mac, ctrl-guest-offloads, guest-csum, csum
+ Host features: protocol-features, event-idx, indirect-desc, version-1, any-layout,
+ notify-on-empty, gso, ctrl-mac-addr, guest-announce, ctrl-rx-extra, ctrl-vlan,
+ ctrl-rx, ctrl-vq, status, mrg-rxbuf, host-ufo, host-ecn, host-tso6, host-tso4,
+ guest-ufo, guest-ecn, guest-tso6, guest-tso4, mac, ctrl-guest-offloads,
+ guest-csum, csum
+ Backend features: protocol-features, event-idx, indirect-desc, version-1, any-layout,
+ notify-on-empty, gso, ctrl-mac-addr, guest-announce, ctrl-rx-extra, ctrl-vlan,
+ ctrl-rx, ctrl-vq, status, mrg-rxbuf, host-ufo, host-ecn, host-tso6, host-tso4,
+ guest-ufo, guest-ecn, guest-tso6, guest-tso4, mac, ctrl-guest-offloads,
+ guest-csum, csum
+ VHost:
+ nvqs: 2
+ vq_index: 0
+ max_queues: 1
+ n_mem_sections: 4
+ n_tmp_sections: 4
+ backend_cap: 2
+ log_enabled: false
+ log_size: 0
+ Features: event-idx, indirect-desc, iommu-platform, version-1, any-layout,
+ notify-on-empty, log-all, mrg-rxbuf
+ Acked features: event-idx, indirect-desc, version-1, mrg-rxbuf
+ Backend features:
+ Protocol features:
+
+ERST
+
+ {
+ .name = "virtio-queue-status",
+ .args_type = "path:s,queue:i",
+ .params = "path queue",
+ .help = "Display status of a given virtio queue",
+ .cmd = hmp_virtio_queue_status,
+ .flags = "p",
+ },
+
+SRST
+ ``info virtio-queue-status`` *path* *queue*
+ Display status of a given virtio queue
+
+ Example:
+
+ Dump the status of the 6th queue of virtio-scsi::
+
+ (qemu) info virtio-queue-status /machine/peripheral-anon/device[2]/virtio-backend 5
+ /machine/peripheral-anon/device[2]/virtio-backend:
+ device_name: virtio-scsi
+ queue_index: 5
+ inuse: 0
+ used_idx: 605
+ signalled_used: 605
+ signalled_used_valid: true
+ last_avail_idx: 605
+ shadow_avail_idx: 605
+ VRing:
+ num: 256
+ num_default: 256
+ align: 4096
+ desc: 0x000000011f0bc000
+ avail: 0x000000011f0bd000
+ used: 0x000000011f0bd240
+
+ERST
+
+ {
+ .name = "virtio-vhost-queue-status",
+ .args_type = "path:s,queue:i",
+ .params = "path queue",
+ .help = "Display status of a given vhost queue",
+ .cmd = hmp_vhost_queue_status,
+ .flags = "p",
+ },
+
+SRST
+ ``info virtio-vhost-queue-status`` *path* *queue*
+ Display status of a given vhost queue
+
+ Example:
+
+ (qemu) info virtio-vhost-queue-status /machine/peripheral/vsock0/virtio-backend 1
+ /machine/peripheral/vsock0/virtio-backend:
+ device_name: vhost-vsock (vhost)
+ kick: 0
+ call: 0
+ VRing:
+ num: 128
+ desc: 0x00007f44fe5b2000
+ desc_phys: 0x000000011f3fb000
+ desc_size: 2048
+ avail: 0x00007f44fe5b2800
+ avail_phys: 0x000000011f3fb800
+ avail_size: 262
+ used: 0x00007f44fe5b2940
+ used_phys: 0x000000011f3fb940
+ used_size: 1030
+
+ERST
+
+ {
+ .name = "virtio-queue-element",
+ .args_type = "path:s,queue:i,index:i?",
+ .params = "path queue [index]",
+ .help = "Display element of a given virtio queue",
+ .cmd = hmp_virtio_queue_element,
+ .flags = "p",
+ },
+
+SRST
+ ``info virtio-queue-element`` *path* *queue* [*index*]
+ Display element of a given virtio queue
+
+ Example:
+
+ Dump the information of the head element of the first queue of
+ virtio-net (vhost on)::
+
+ (qemu) info virtio-queue-element /machine/peripheral-anon/device[1]/virtio-backend 0
+ /machine/peripheral-anon/device[1]/virtio-backend:
+ device_name: virtio-net
+ index: 0
+ desc:
+ ndescs: 1
+ descs: addr 0x1312c8000 len 1536 (write)
+ avail:
+ flags: 0
+ idx: 256
+ ring: 0
+ used:
+ flags: 0
+ idx: 32
+
+ Since device[1] is a virtio-net device, we can see the MAC address
+ of the NIC in the element buffer::
+
+ (qemu) xp/128bx 0x1312c8000
+ 00000001312c8000: 0x01 0x00 0x00 0x00 0x00 0x00 0x22 0x00
+ 00000001312c8008: 0x06 0x00 0x01 0x00 0x52 0x54 0x00 0x12
+ 00000001312c8010: 0x34 0x56 0xe6 0x94 0xf2 0xc1 0x51 0x2a
+ ...
+
+ [root@guest: ~]# ip link show eth0
+ 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode
+ DEFAULT group default qlen 1000
+ link/ether 52:54:00:12:34:56 brd ff:ff:ff:ff:ff:ff
+
+ And we can see the MAC address of the gateway immediately after::
+
+ [root@guest: ~]# arp -a
+ gateway (192.168.53.1) at e6:94:f2:c1:51:2a [ether] on eth0
+
+ERST
@@ -95,6 +95,11 @@ void hmp_qom_list(Monitor *mon, const QDict *qdict);
void hmp_qom_get(Monitor *mon, const QDict *qdict);
void hmp_qom_set(Monitor *mon, const QDict *qdict);
void hmp_info_qom_tree(Monitor *mon, const QDict *dict);
+void hmp_virtio_query(Monitor *mon, const QDict *qdict);
+void hmp_virtio_status(Monitor *mon, const QDict *qdict);
+void hmp_virtio_queue_status(Monitor *mon, const QDict *qdict);
+void hmp_vhost_queue_status(Monitor *mon, const QDict *qdict);
+void hmp_virtio_queue_element(Monitor *mon, const QDict *qdict);
void object_add_completion(ReadLineState *rs, int nb_args, const char *str);
void object_del_completion(ReadLineState *rs, int nb_args, const char *str);
void device_add_completion(ReadLineState *rs, int nb_args, const char *str);
@@ -42,6 +42,8 @@
#include "qapi/qapi-commands-run-state.h"
#include "qapi/qapi-commands-tpm.h"
#include "qapi/qapi-commands-ui.h"
+#include "qapi/qapi-commands-virtio.h"
+#include "qapi/qapi-visit-virtio.h"
#include "qapi/qapi-visit-net.h"
#include "qapi/qapi-visit-migration.h"
#include "qapi/qmp/qdict.h"
@@ -2165,3 +2167,359 @@ void hmp_info_memory_size_summary(Monitor *mon, const QDict *qdict)
}
hmp_handle_error(mon, err);
}
+
+#define DUMP_FEATURES(type, field) \
+ do { \
+ type##FeatureList *list = features->u.field.features; \
+ if (list) { \
+ monitor_printf(mon, " "); \
+ while (list) { \
+ monitor_printf(mon, "%s", type##Feature_str(list->value));\
+ list = list->next; \
+ if (list != NULL) { \
+ monitor_printf(mon, ", "); \
+ } \
+ } \
+ monitor_printf(mon, "\n"); \
+ } \
+ } while (0)
+
+static void hmp_virtio_dump_protocols(Monitor *mon,
+ VhostDeviceProtocols *pcol)
+{
+ VhostProtocolFeatureList *pcol_list = pcol->features;
+ while (pcol_list) {
+ monitor_printf(mon, "%s",
+ VhostProtocolFeature_str(pcol_list->value));
+ pcol_list = pcol_list->next;
+ if (pcol_list != NULL) {
+ monitor_printf(mon, ", ");
+ }
+ }
+ monitor_printf(mon, "\n");
+ if (pcol->has_unknown_protocols) {
+ monitor_printf(mon, " unknown-protocols(0x%016"PRIx64")\n",
+ pcol->unknown_protocols);
+ }
+}
+
+static void hmp_virtio_dump_status(Monitor *mon,
+ VirtioDeviceStatus *status)
+{
+ VirtioConfigStatusList *status_list = status->dev_status;
+ while (status_list) {
+ monitor_printf(mon, "%s",
+ VirtioConfigStatus_str(status_list->value));
+ status_list = status_list->next;
+ if (status_list != NULL) {
+ monitor_printf(mon, ", ");
+ }
+ }
+ monitor_printf(mon, "\n");
+ if (status->has_unknown_statuses) {
+ monitor_printf(mon, " unknown-statuses(0x%016"PRIx32")\n",
+ status->unknown_statuses);
+ }
+}
+
+static void hmp_virtio_dump_features(Monitor *mon,
+ VirtioDeviceFeatures *features)
+{
+ VirtioTransportFeatureList *transport_list = features->transport;
+ while (transport_list) {
+ monitor_printf(mon, "%s",
+ VirtioTransportFeature_str(transport_list->value));
+ transport_list = transport_list->next;
+ if (transport_list != NULL) {
+ monitor_printf(mon, ", ");
+ }
+ }
+ monitor_printf(mon, "\n");
+ switch (features->type) {
+ case VIRTIO_TYPE_VIRTIO_SERIAL:
+ DUMP_FEATURES(VirtioSerial, virtio_serial);
+ break;
+ case VIRTIO_TYPE_VIRTIO_BLK:
+ DUMP_FEATURES(VirtioBlk, virtio_blk);
+ break;
+ case VIRTIO_TYPE_VIRTIO_GPU:
+ DUMP_FEATURES(VirtioGpu, virtio_gpu);
+ break;
+ case VIRTIO_TYPE_VIRTIO_NET:
+ DUMP_FEATURES(VirtioNet, virtio_net);
+ break;
+ case VIRTIO_TYPE_VIRTIO_SCSI:
+ DUMP_FEATURES(VirtioScsi, virtio_scsi);
+ break;
+ case VIRTIO_TYPE_VIRTIO_BALLOON:
+ DUMP_FEATURES(VirtioBalloon, virtio_balloon);
+ break;
+ case VIRTIO_TYPE_VIRTIO_IOMMU:
+ DUMP_FEATURES(VirtioIommu, virtio_iommu);
+ break;
+ case VIRTIO_TYPE_VIRTIO_INPUT:
+ DUMP_FEATURES(VirtioInput, virtio_input);
+ break;
+ case VIRTIO_TYPE_VHOST_USER_FS:
+ DUMP_FEATURES(VhostUserFs, vhost_user_fs);
+ break;
+ case VIRTIO_TYPE_VHOST_VSOCK:
+ DUMP_FEATURES(VhostVsock, vhost_vsock);
+ break;
+ case VIRTIO_TYPE_VIRTIO_CRYPTO:
+ DUMP_FEATURES(VirtioCrypto, virtio_crypto);
+ break;
+ case VIRTIO_TYPE_VIRTIO_MEM:
+ DUMP_FEATURES(VirtioMem, virtio_mem);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ if (features->has_unknown_features) {
+ monitor_printf(mon, " unknown-features(0x%016"PRIx64")\n",
+ features->unknown_features);
+ }
+}
+
+void hmp_virtio_query(Monitor *mon, const QDict *qdict)
+{
+ Error *err = NULL;
+ VirtioInfoList *list = qmp_x_query_virtio(&err);
+ VirtioInfoList *node;
+
+ if (err != NULL) {
+ hmp_handle_error(mon, err);
+ return;
+ }
+
+ if (list == NULL) {
+ monitor_printf(mon, "No VirtIO devices\n");
+ return;
+ }
+
+ node = list;
+ while (node) {
+ monitor_printf(mon, "%s [%s]\n", node->value->path,
+ node->value->type);
+ node = node->next;
+ }
+ qapi_free_VirtioInfoList(list);
+}
+
+void hmp_virtio_status(Monitor *mon, const QDict *qdict)
+{
+ Error *err = NULL;
+ const char *path = qdict_get_try_str(qdict, "path");
+ VirtioStatus *s = qmp_x_query_virtio_status(path, &err);
+
+ if (err != NULL) {
+ hmp_handle_error(mon, err);
+ return;
+ }
+
+ monitor_printf(mon, "%s:\n", path);
+ monitor_printf(mon, " device_name: %s %s\n",
+ s->name, s->has_vhost_dev ? "(vhost)" : "");
+ monitor_printf(mon, " device_id: %d\n", s->device_id);
+ monitor_printf(mon, " vhost_started: %s\n",
+ s->vhost_started ? "true" : "false");
+ monitor_printf(mon, " bus_name: %s\n", s->bus_name);
+ monitor_printf(mon, " broken: %s\n",
+ s->broken ? "true" : "false");
+ monitor_printf(mon, " disabled: %s\n",
+ s->disabled ? "true" : "false");
+ monitor_printf(mon, " disable_legacy_check: %s\n",
+ s->disable_legacy_check ? "true" : "false");
+ monitor_printf(mon, " started: %s\n",
+ s->started ? "true" : "false");
+ monitor_printf(mon, " use_started: %s\n",
+ s->use_started ? "true" : "false");
+ monitor_printf(mon, " start_on_kick: %s\n",
+ s->start_on_kick ? "true" : "false");
+ monitor_printf(mon, " use_guest_notifier_mask: %s\n",
+ s->use_guest_notifier_mask ? "true" : "false");
+ monitor_printf(mon, " vm_running: %s\n",
+ s->vm_running ? "true" : "false");
+ monitor_printf(mon, " num_vqs: %ld\n", s->num_vqs);
+ monitor_printf(mon, " queue_sel: %d\n",
+ s->queue_sel);
+ monitor_printf(mon, " isr: %d\n", s->isr);
+ monitor_printf(mon, " endianness: %s\n",
+ VirtioStatusEndianness_str(s->device_endian));
+ monitor_printf(mon, " status: ");
+ hmp_virtio_dump_status(mon, s->status);
+ monitor_printf(mon, " Guest features: ");
+ hmp_virtio_dump_features(mon, s->guest_features);
+ monitor_printf(mon, " Host features: ");
+ hmp_virtio_dump_features(mon, s->host_features);
+ monitor_printf(mon, " Backend features: ");
+ hmp_virtio_dump_features(mon, s->backend_features);
+
+ if (s->has_vhost_dev) {
+ monitor_printf(mon, " VHost:\n");
+ monitor_printf(mon, " nvqs: %d\n",
+ s->vhost_dev->nvqs);
+ monitor_printf(mon, " vq_index: %ld\n",
+ s->vhost_dev->vq_index);
+ monitor_printf(mon, " max_queues: %lu\n",
+ s->vhost_dev->max_queues);
+ monitor_printf(mon, " n_mem_sections: %ld\n",
+ s->vhost_dev->n_mem_sections);
+ monitor_printf(mon, " n_tmp_sections: %ld\n",
+ s->vhost_dev->n_tmp_sections);
+ monitor_printf(mon, " backend_cap: %lu\n",
+ s->vhost_dev->backend_cap);
+ monitor_printf(mon, " log_enabled: %s\n",
+ s->vhost_dev->log_enabled ? "true" : "false");
+ monitor_printf(mon, " log_size: %lu\n",
+ s->vhost_dev->log_size);
+ monitor_printf(mon, " Features: ");
+ hmp_virtio_dump_features(mon, s->vhost_dev->features);
+ monitor_printf(mon, " Acked features: ");
+ hmp_virtio_dump_features(mon, s->vhost_dev->acked_features);
+ monitor_printf(mon, " Backend features: ");
+ hmp_virtio_dump_features(mon, s->vhost_dev->backend_features);
+ monitor_printf(mon, " Protocol features: ");
+ hmp_virtio_dump_protocols(mon, s->vhost_dev->protocol_features);
+ }
+
+ qapi_free_VirtioStatus(s);
+}
+
+void hmp_vhost_queue_status(Monitor *mon, const QDict *qdict)
+{
+ Error *err = NULL;
+ const char *path = qdict_get_try_str(qdict, "path");
+ int queue = qdict_get_int(qdict, "queue");
+ VirtVhostQueueStatus *s =
+ qmp_x_query_virtio_vhost_queue_status(path, queue, &err);
+
+ if (err != NULL) {
+ hmp_handle_error(mon, err);
+ return;
+ }
+
+ monitor_printf(mon, "%s:\n", path);
+ monitor_printf(mon, " device_name: %s (vhost)\n",
+ s->device_name);
+ monitor_printf(mon, " kick: %ld\n", s->kick);
+ monitor_printf(mon, " call: %ld\n", s->call);
+ monitor_printf(mon, " VRing:\n");
+ monitor_printf(mon, " num: %ld\n", s->num);
+ monitor_printf(mon, " desc: 0x%016"PRIx64"\n", s->desc);
+ monitor_printf(mon, " desc_phys: 0x%016"PRIx64"\n",
+ s->desc_phys);
+ monitor_printf(mon, " desc_size: %"PRId32"\n", s->desc_size);
+ monitor_printf(mon, " avail: 0x%016"PRIx64"\n", s->avail);
+ monitor_printf(mon, " avail_phys: 0x%016"PRIx64"\n",
+ s->avail_phys);
+ monitor_printf(mon, " avail_size: %"PRId32"\n", s->avail_size);
+ monitor_printf(mon, " used: 0x%016"PRIx64"\n", s->used);
+ monitor_printf(mon, " used_phys: 0x%016"PRIx64"\n",
+ s->used_phys);
+ monitor_printf(mon, " used_size: %"PRId32"\n", s->used_size);
+
+ qapi_free_VirtVhostQueueStatus(s);
+}
+
+void hmp_virtio_queue_status(Monitor *mon, const QDict *qdict)
+{
+ Error *err = NULL;
+ const char *path = qdict_get_try_str(qdict, "path");
+ int queue = qdict_get_int(qdict, "queue");
+ VirtQueueStatus *s = qmp_x_query_virtio_queue_status(path, queue, &err);
+
+ if (err != NULL) {
+ hmp_handle_error(mon, err);
+ return;
+ }
+
+ monitor_printf(mon, "%s:\n", path);
+ monitor_printf(mon, " device_name: %s\n", s->device_name);
+ monitor_printf(mon, " queue_index: %d\n", s->queue_index);
+ monitor_printf(mon, " inuse: %d\n", s->inuse);
+ monitor_printf(mon, " used_idx: %d\n", s->used_idx);
+ monitor_printf(mon, " signalled_used: %d\n",
+ s->signalled_used);
+ monitor_printf(mon, " signalled_used_valid: %s\n",
+ s->signalled_used_valid ? "true" : "false");
+ if (s->has_last_avail_idx) {
+ monitor_printf(mon, " last_avail_idx: %d\n",
+ s->last_avail_idx);
+ }
+ if (s->has_shadow_avail_idx) {
+ monitor_printf(mon, " shadow_avail_idx: %d\n",
+ s->shadow_avail_idx);
+ }
+ monitor_printf(mon, " VRing:\n");
+ monitor_printf(mon, " num: %"PRId32"\n", s->vring_num);
+ monitor_printf(mon, " num_default: %"PRId32"\n",
+ s->vring_num_default);
+ monitor_printf(mon, " align: %"PRId32"\n",
+ s->vring_align);
+ monitor_printf(mon, " desc: 0x%016"PRIx64"\n",
+ s->vring_desc);
+ monitor_printf(mon, " avail: 0x%016"PRIx64"\n",
+ s->vring_avail);
+ monitor_printf(mon, " used: 0x%016"PRIx64"\n",
+ s->vring_used);
+
+ qapi_free_VirtQueueStatus(s);
+}
+
+void hmp_virtio_queue_element(Monitor *mon, const QDict *qdict)
+{
+ Error *err = NULL;
+ const char *path = qdict_get_try_str(qdict, "path");
+ int queue = qdict_get_int(qdict, "queue");
+ int index = qdict_get_try_int(qdict, "index", -1);
+ VirtioQueueElement *e;
+ VirtioRingDescList *list;
+
+ e = qmp_x_query_virtio_queue_element(path, queue, index != -1,
+ index, &err);
+ if (err != NULL) {
+ hmp_handle_error(mon, err);
+ return;
+ }
+
+ monitor_printf(mon, "%s:\n", path);
+ monitor_printf(mon, " device_name: %s\n", e->device_name);
+ monitor_printf(mon, " index: %d\n", e->index);
+ monitor_printf(mon, " desc:\n");
+ monitor_printf(mon, " ndescs: %d\n", e->ndescs);
+ monitor_printf(mon, " descs: ");
+
+ list = e->descs;
+ while (list) {
+ monitor_printf(mon, "addr 0x%"PRIx64" len %d", list->value->addr,
+ list->value->len);
+ if (list->value->flags) {
+ VirtioRingDescFlagsList *flag = list->value->flags;
+ monitor_printf(mon, " (");
+ while (flag) {
+ monitor_printf(mon, "%s",
+ VirtioRingDescFlags_str(flag->value));
+ flag = flag->next;
+ if (flag) {
+ monitor_printf(mon, ", ");
+ }
+ }
+ monitor_printf(mon, ")");
+ }
+ list = list->next;
+ if (list) {
+ monitor_printf(mon, ", ");
+ }
+ }
+ monitor_printf(mon, "\n");
+ monitor_printf(mon, " avail:\n");
+ monitor_printf(mon, " flags: %d\n", e->avail->flags);
+ monitor_printf(mon, " idx: %d\n", e->avail->idx);
+ monitor_printf(mon, " ring: %d\n", e->avail->ring);
+ monitor_printf(mon, " used:\n");
+ monitor_printf(mon, " flags: %d\n", e->used->flags);
+ monitor_printf(mon, " idx: %d\n", e->used->idx);
+
+ qapi_free_VirtioQueueElement(e);
+}