From 14316ce0b17a24091718536aae859b1ae3abaf77 Mon Sep 17 00:00:00 2001 From: Julio Montes Date: Tue, 24 Oct 2017 08:57:58 -0500 Subject: [PATCH] qemu/qmp: Implement function to hot plug PCI devices ExecutePCIDeviceAdd is a function that can be used to hot plug devices directly on pci(e).0 or pci(e) bridges. ExecutePCIDeviceAdd is PCI specific because unlike ExecuteDeviceAdd, it includes an extra parameter to specify the device address on its parent bus. Signed-off-by: Julio Montes --- qmp.go | 16 ++++++++++++++++ qmp_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/qmp.go b/qmp.go index 5cc19af0e..ec2910444 100644 --- a/qmp.go +++ b/qmp.go @@ -675,3 +675,19 @@ func (q *QMP) ExecuteDeviceDel(ctx context.Context, devID string) error { } return q.executeCommand(ctx, "device_del", args, filter) } + +// ExecutePCIDeviceAdd is the PCI version of ExecuteDeviceAdd. This function can be used +// to hot plug PCI devices on PCI(E) bridges, unlike ExecuteDeviceAdd this function receive the +// device address on its parent bus. bus is optional. +func (q *QMP) ExecutePCIDeviceAdd(ctx context.Context, blockdevID, devID, driver, addr, bus string) error { + args := map[string]interface{}{ + "id": devID, + "driver": driver, + "drive": blockdevID, + "addr": addr, + } + if bus != "" { + args["bus"] = bus + } + return q.executeCommand(ctx, "device_add", args, nil) +} diff --git a/qmp_test.go b/qmp_test.go index 5b63b1707..e8072431c 100644 --- a/qmp_test.go +++ b/qmp_test.go @@ -785,3 +785,28 @@ func TestQMPLostLoop(t *testing.T) { t.Error("Expected executeQMPCapabilities to fail") } } + +// Checks that PCI 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 TestQMPPCIDeviceAdd(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) + blockdevID := fmt.Sprintf("drive_%s", testutil.VolumeUUID) + devID := fmt.Sprintf("device_%s", testutil.VolumeUUID) + err := q.ExecutePCIDeviceAdd(context.Background(), blockdevID, devID, + "virtio-blk-pci", "0x1", "") + if err != nil { + t.Fatalf("Unexpected error %v", err) + } + q.Shutdown() + <-disconnectedCh +}