diff --git a/qemu/qmp.go b/qemu/qmp.go index a22edba127..9d27dbeefb 100644 --- a/qemu/qmp.go +++ b/qemu/qmp.go @@ -1135,6 +1135,27 @@ func (q *QMP) ExecutePCIDeviceAdd(ctx context.Context, blockdevID, devID, driver return q.executeCommand(ctx, "device_add", args, nil) } +// ExecutePCIVhostUserDevAdd adds a vhost-user device to a QEMU instance using the device_add command. +// This function can be used to hot plug vhost-user devices on PCI(E) bridges. +// It receives the bus and the device address on its parent bus. bus is optional. +// devID is the id of the device to add.Must be valid QMP identifier. chardevID +// is the QMP identifier of character device using a unix socket as backend. +// driver is the name of vhost-user driver, like vhost-user-blk-pci. +func (q *QMP) ExecutePCIVhostUserDevAdd(ctx context.Context, driver, devID, chardevID, addr, bus string) error { + args := map[string]interface{}{ + "driver": driver, + "id": devID, + "chardev": chardevID, + "addr": addr, + } + + if bus != "" { + args["bus"] = bus + } + + return q.executeCommand(ctx, "device_add", args, nil) +} + // ExecuteVFIODeviceAdd adds a VFIO device to a QEMU instance // using the device_add command. devID is the id of the device to add. // Must be valid QMP identifier. bdf is the PCI bus-device-function diff --git a/qemu/qmp_test.go b/qemu/qmp_test.go index 8137910a87..71f97bcadd 100644 --- a/qemu/qmp_test.go +++ b/qemu/qmp_test.go @@ -1329,6 +1329,26 @@ func TestExecutePCIVSockAdd(t *testing.T) { <-disconnectedCh } +// Checks vhost-user-pci hotplug +func TestExecutePCIVhostUserDevAdd(t *testing.T) { + connectedCh := make(chan *QMPVersion) + disconnectedCh := make(chan struct{}) + buf := newQMPTestCommandBuffer(t) + buf.AddCommand("device_add", nil, "return", nil) + cfg := QMPConfig{Logger: qmpTestLogger{}} + q := startQMPLoop(buf, cfg, connectedCh, disconnectedCh) + checkVersion(t, connectedCh) + driver := "vhost-user-blk-pci" + devID := "vhost-user-blk0" + chardevID := "vhost-user-blk-char0" + err := q.ExecutePCIVhostUserDevAdd(context.Background(), driver, devID, chardevID, "1", "1") + if err != nil { + t.Fatalf("Unexpected error %v", err) + } + q.Shutdown() + <-disconnectedCh +} + // Checks getfd func TestExecuteGetFdD(t *testing.T) { connectedCh := make(chan *QMPVersion)