From 13aeba09d56ce44e531cd0aaf531f01fe11acaee Mon Sep 17 00:00:00 2001 From: Liu Xiaodong Date: Tue, 14 Jan 2020 00:09:52 -0500 Subject: [PATCH 1/2] qmp: support command 'chardev-remove' So that caller can remove hotremove chardev via qmp Signed-off-by: Liu Xiaodong --- qemu/qmp.go | 11 +++++++++++ qemu/qmp_test.go | 22 ++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/qemu/qmp.go b/qemu/qmp.go index 473ce4afaa..a22edba127 100644 --- a/qemu/qmp.go +++ b/qemu/qmp.go @@ -946,6 +946,17 @@ func (q *QMP) ExecuteBlockdevDel(ctx context.Context, blockdevID string) error { return q.executeCommand(ctx, "x-blockdev-del", args, nil) } +// ExecuteChardevDel deletes a char device by sending a chardev-remove command. +// chardevID is the id of the char device to be deleted. Typically, this will +// match the id passed to ExecuteCharDevUnixSocketAdd. It must be a valid QMP id. +func (q *QMP) ExecuteChardevDel(ctx context.Context, chardevID string) error { + args := map[string]interface{}{ + "id": chardevID, + } + + return q.executeCommand(ctx, "chardev-remove", args, nil) +} + // ExecuteNetdevAdd adds a Net device to a QEMU instance // using the netdev_add command. netdevID is the id of the device to add. // Must be valid QMP identifier. diff --git a/qemu/qmp_test.go b/qemu/qmp_test.go index c5722765ab..8137910a87 100644 --- a/qemu/qmp_test.go +++ b/qemu/qmp_test.go @@ -638,6 +638,28 @@ func TestQMPBlockdevDel(t *testing.T) { <-disconnectedCh } +// Checks that the chardev-remove command is correctly sent. +// +// We start a QMPLoop, send the chardev-remove command and stop the loop. +// +// The chardev-remove command should be correctly sent and the QMP loop should +// exit gracefully. +func TestQMPChardevDel(t *testing.T) { + connectedCh := make(chan *QMPVersion) + disconnectedCh := make(chan struct{}) + buf := newQMPTestCommandBuffer(t) + buf.AddCommand("chardev-remove", nil, "return", nil) + cfg := QMPConfig{Logger: qmpTestLogger{}} + q := startQMPLoop(buf, cfg, connectedCh, disconnectedCh) + q.version = checkVersion(t, connectedCh) + err := q.ExecuteChardevDel(context.Background(), "chardev-0") + if err != nil { + t.Fatalf("Unexpected error %v", err) + } + q.Shutdown() + <-disconnectedCh +} + // Checks that the device_del command is correctly sent. // // We start a QMPLoop, send the device_del command and wait for it to complete. From e04be2cc3819c3b6822513262aeb4db24c395f8d Mon Sep 17 00:00:00 2001 From: Liu Xiaodong Date: Tue, 14 Jan 2020 00:13:26 -0500 Subject: [PATCH 2/2] qmp: add ExecutePCIVhostUserDevAdd API Caller can hotplug vhost-user device via qmp. The Qemu vhost-user device, like vhost-user-blk-pci and vhost-user-scsi-pci can be hotplugged by qmp API: ExecuteCharDevUnixSocketAdd() together with ExecutePCIVhostUserDevAdd() Signed-off-by: Liu Xiaodong --- qemu/qmp.go | 21 +++++++++++++++++++++ qemu/qmp_test.go | 20 ++++++++++++++++++++ 2 files changed, 41 insertions(+) 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)