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 <julio.montes@intel.com>
This commit is contained in:
Julio Montes 2017-10-24 08:57:58 -05:00
parent 83485dc9a4
commit 14316ce0b1
2 changed files with 41 additions and 0 deletions

16
qmp.go
View File

@ -675,3 +675,19 @@ func (q *QMP) ExecuteDeviceDel(ctx context.Context, devID string) error {
} }
return q.executeCommand(ctx, "device_del", args, filter) 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)
}

View File

@ -785,3 +785,28 @@ func TestQMPLostLoop(t *testing.T) {
t.Error("Expected executeQMPCapabilities to fail") 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
}