diff --git a/qemu/qmp.go b/qemu/qmp.go index e5dbb9318..002ea42cf 100644 --- a/qemu/qmp.go +++ b/qemu/qmp.go @@ -837,6 +837,24 @@ func (q *QMP) ExecutePCIVFIODeviceAdd(ctx context.Context, devID, bdf, addr, bus return q.executeCommand(ctx, "device_add", args, nil) } +// ExecutePCIVFIOMediatedDeviceAdd adds a VFIO mediated device to a QEMU instance using the device_add command. +// This function can be used to hot plug VFIO mediated devices on PCI(E) bridges, unlike +// ExecuteVFIODeviceAdd this function 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. sysfsdev is the VFIO +// mediated device. +func (q *QMP) ExecutePCIVFIOMediatedDeviceAdd(ctx context.Context, devID, sysfsdev, addr, bus string) error { + args := map[string]interface{}{ + "id": devID, + "driver": "vfio-pci", + "sysfsdev": sysfsdev, + "addr": addr, + } + if bus != "" { + args["bus"] = bus + } + return q.executeCommand(ctx, "device_add", args, nil) +} + // ExecuteCPUDeviceAdd adds a CPU to a QEMU instance using the device_add command. // driver is the CPU model, cpuID must be a unique ID to identify the CPU, socketID is the socket number within // node/board the CPU belongs to, coreID is the core number within socket the CPU belongs to, threadID is the diff --git a/qemu/qmp_test.go b/qemu/qmp_test.go index 3733918e1..8e1bce381 100644 --- a/qemu/qmp_test.go +++ b/qemu/qmp_test.go @@ -892,6 +892,30 @@ func TestQMPPCIDeviceAdd(t *testing.T) { <-disconnectedCh } +// Checks that PCI VFIO mediated devices are correctly added using device_add. +// +// We start a QMPLoop, send the device_add command and stop the loop. +// +// The device_add command should be correctly sent and the QMP loop should +// exit gracefully. +func TestQMPPCIVFIOMediatedDeviceAdd(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) + sysfsDev := "/sys/bus/pci/devices/0000:00:02.0/a297db4a-f4c2-11e6-90f6-d3b88d6c9525" + devID := fmt.Sprintf("device_%s", volumeUUID) + err := q.ExecutePCIVFIOMediatedDeviceAdd(context.Background(), devID, sysfsDev, "0x1", "") + if err != nil { + t.Fatalf("Unexpected error %v", err) + } + q.Shutdown() + <-disconnectedCh +} + // Checks that CPU are correctly added using device_add func TestQMPCPUDeviceAdd(t *testing.T) { connectedCh := make(chan *QMPVersion)