vfio-user: implement message send infrastructure

Add plumbing for sending vfio-user messages on the control socket.
Add initial version negotation on connection.

Originally-by: John Johnson <john.g.johnson@oracle.com>
Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
Signed-off-by: John Levon <john.levon@nutanix.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Link: https://lore.kernel.org/qemu-devel/20250625193012.2316242-5-john.levon@nutanix.com
Signed-off-by: Cédric Le Goater <clg@redhat.com>
This commit is contained in:
John Levon
2025-06-26 08:55:38 +02:00
committed by Cédric Le Goater
parent 0b3d881a06
commit 36227628d8
5 changed files with 606 additions and 2 deletions
+18 -2
View File
@@ -20,6 +20,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(VFIOUserPCIDevice, VFIO_USER_PCI)
struct VFIOUserPCIDevice {
VFIOPCIDevice device;
SocketAddress *socket;
bool send_queued; /* all sends are queued */
};
/*
@@ -92,6 +93,16 @@ static void vfio_user_pci_realize(PCIDevice *pdev, Error **errp)
vbasedev->proxy = proxy;
vfio_user_set_handler(vbasedev, vfio_user_pci_process_req, vdev);
vbasedev->name = g_strdup_printf("vfio-user:%s", sock_name);
if (udev->send_queued) {
proxy->flags |= VFIO_PROXY_FORCE_QUEUED;
}
if (!vfio_user_validate_version(proxy, errp)) {
goto error;
}
/*
* vfio-user devices are effectively mdevs (don't use a host iommu).
*/
@@ -101,9 +112,13 @@ static void vfio_user_pci_realize(PCIDevice *pdev, Error **errp)
if (!vfio_device_attach_by_iommu_type(TYPE_VFIO_IOMMU_USER,
vbasedev->name, vbasedev,
as, errp)) {
error_prepend(errp, VFIO_MSG_PREFIX, vbasedev->name);
return;
goto error;
}
return;
error:
error_prepend(errp, VFIO_MSG_PREFIX, vdev->vbasedev.name);
}
static void vfio_user_instance_init(Object *obj)
@@ -153,6 +168,7 @@ static const Property vfio_user_pci_dev_properties[] = {
sub_vendor_id, PCI_ANY_ID),
DEFINE_PROP_UINT32("x-pci-sub-device-id", VFIOPCIDevice,
sub_device_id, PCI_ANY_ID),
DEFINE_PROP_BOOL("x-send-queued", VFIOUserPCIDevice, send_queued, false),
};
static void vfio_user_pci_set_socket(Object *obj, Visitor *v, const char *name,
+62
View File
@@ -50,4 +50,66 @@ enum vfio_user_command {
#define VFIO_USER_NO_REPLY 0x10
#define VFIO_USER_ERROR 0x20
/*
* VFIO_USER_VERSION
*/
typedef struct {
VFIOUserHdr hdr;
uint16_t major;
uint16_t minor;
char capabilities[];
} VFIOUserVersion;
#define VFIO_USER_MAJOR_VER 0
#define VFIO_USER_MINOR_VER 0
#define VFIO_USER_CAP "capabilities"
/* "capabilities" members */
#define VFIO_USER_CAP_MAX_FDS "max_msg_fds"
#define VFIO_USER_CAP_MAX_XFER "max_data_xfer_size"
#define VFIO_USER_CAP_PGSIZES "pgsizes"
#define VFIO_USER_CAP_MAP_MAX "max_dma_maps"
#define VFIO_USER_CAP_MIGR "migration"
/* "migration" members */
#define VFIO_USER_CAP_PGSIZE "pgsize"
#define VFIO_USER_CAP_MAX_BITMAP "max_bitmap_size"
/*
* Max FDs mainly comes into play when a device supports multiple interrupts
* where each ones uses an eventfd to inject it into the guest.
* It is clamped by the the number of FDs the qio channel supports in a
* single message.
*/
#define VFIO_USER_DEF_MAX_FDS 8
#define VFIO_USER_MAX_MAX_FDS 16
/*
* Max transfer limits the amount of data in region and DMA messages.
* Region R/W will be very small (limited by how much a single instruction
* can process) so just use a reasonable limit here.
*/
#define VFIO_USER_DEF_MAX_XFER (1024 * 1024)
#define VFIO_USER_MAX_MAX_XFER (64 * 1024 * 1024)
/*
* Default pagesizes supported is 4k.
*/
#define VFIO_USER_DEF_PGSIZE 4096
/*
* Default max number of DMA mappings is stolen from the
* linux kernel "dma_entry_limit"
*/
#define VFIO_USER_DEF_MAP_MAX 65535
/*
* Default max bitmap size is also take from the linux kernel,
* where usage of signed ints limits the VA range to 2^31 bytes.
* Dividing that by the number of bits per byte yields 256MB
*/
#define VFIO_USER_DEF_MAX_BITMAP (256 * 1024 * 1024)
#endif /* VFIO_USER_PROTOCOL_H */
File diff suppressed because it is too large Load Diff
+9
View File
@@ -37,6 +37,7 @@ typedef struct VFIOUserMsg {
uint32_t id;
QemuCond cv;
bool complete;
bool pending;
enum msg_type type;
} VFIOUserMsg;
@@ -56,6 +57,12 @@ typedef struct VFIOUserProxy {
struct QIOChannel *ioc;
void (*request)(void *opaque, VFIOUserMsg *msg);
void *req_arg;
uint64_t max_xfer_size;
uint64_t max_send_fds;
uint64_t max_dma;
uint64_t dma_pgsizes;
uint64_t max_bitmap;
uint64_t migr_pgsize;
int flags;
QemuCond close_cv;
AioContext *ctx;
@@ -78,6 +85,7 @@ typedef struct VFIOUserProxy {
/* VFIOProxy flags */
#define VFIO_PROXY_CLIENT 0x1
#define VFIO_PROXY_FORCE_QUEUED 0x4
typedef struct VFIODevice VFIODevice;
@@ -86,5 +94,6 @@ void vfio_user_disconnect(VFIOUserProxy *proxy);
void vfio_user_set_handler(VFIODevice *vbasedev,
void (*handler)(void *opaque, VFIOUserMsg *msg),
void *reqarg);
bool vfio_user_validate_version(VFIOUserProxy *proxy, Error **errp);
#endif /* VFIO_USER_PROXY_H */
+2
View File
@@ -6,3 +6,5 @@
vfio_user_recv_hdr(const char *name, uint16_t id, uint16_t cmd, uint32_t size, uint32_t flags) " (%s) id 0x%x cmd 0x%x size 0x%x flags 0x%x"
vfio_user_recv_read(uint16_t id, int read) " id 0x%x read 0x%x"
vfio_user_recv_request(uint16_t cmd) " command 0x%x"
vfio_user_send_write(uint16_t id, int wrote) " id 0x%x wrote 0x%x"
vfio_user_version(uint16_t major, uint16_t minor, const char *caps) " major %d minor %d caps: %s"