diff --git a/qemu/qmp.go b/qemu/qmp.go index 32a59ef04b..e5dbb9318c 100644 --- a/qemu/qmp.go +++ b/qemu/qmp.go @@ -727,6 +727,51 @@ func (q *QMP) ExecuteBlockdevDel(ctx context.Context, blockdevID string) error { return q.executeCommand(ctx, "x-blockdev-del", 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. +func (q *QMP) ExecuteNetdevAdd(ctx context.Context, netdevType, netdevID, ifname, downscript, script string, queues int) error { + args := map[string]interface{}{ + "type": netdevType, + "id": netdevID, + "ifname": ifname, + "downscript": downscript, + "script": script, + } + if queues > 1 { + args["queues"] = queues + } + + return q.executeCommand(ctx, "netdev_add", args, nil) +} + +// ExecuteNetdevDel deletes a Net device from a QEMU instance +// using the netdev_del command. netdevID is the id of the device to delete. +func (q *QMP) ExecuteNetdevDel(ctx context.Context, netdevID string) error { + args := map[string]interface{}{ + "id": netdevID, + } + return q.executeCommand(ctx, "netdev_del", args, nil) +} + +// ExecuteNetPCIDeviceAdd adds a Net PCI device to a QEMU instance +// using the device_add command. devID is the id of the device to add. +// Must be valid QMP identifier. netdevID is the id of nic added by previous netdev_add. +func (q *QMP) ExecuteNetPCIDeviceAdd(ctx context.Context, netdevID, devID, macAddr, addr, bus string) error { + args := map[string]interface{}{ + "id": devID, + "driver": VirtioNetPCI, + "netdev": netdevID, + "mac": macAddr, + "addr": addr, + } + + if bus != "" { + args["bus"] = bus + } + return q.executeCommand(ctx, "device_add", args, nil) +} + // ExecuteDeviceDel deletes guest portion of a QEMU device by sending a // device_del command. devId is the identifier of the device to delete. // Typically it would match the devID parameter passed to an earlier call diff --git a/qemu/qmp_test.go b/qemu/qmp_test.go index c87822ae8e..3733918e1e 100644 --- a/qemu/qmp_test.go +++ b/qemu/qmp_test.go @@ -364,6 +364,66 @@ func TestQMPBlockdevAdd(t *testing.T) { <-disconnectedCh } +// Checks that the netdev_add command is correctly sent. +// +// We start a QMPLoop, send the netdev_add command and stop the loop. +// +// The netdev_add command should be correctly sent and the QMP loop should +// exit gracefully. +func TestQMPNetdevAdd(t *testing.T) { + connectedCh := make(chan *QMPVersion) + disconnectedCh := make(chan struct{}) + buf := newQMPTestCommandBuffer(t) + buf.AddCommand("netdev_add", nil, "return", nil) + cfg := QMPConfig{Logger: qmpTestLogger{}} + q := startQMPLoop(buf, cfg, connectedCh, disconnectedCh) + q.version = checkVersion(t, connectedCh) + err := q.ExecuteNetdevAdd(context.Background(), "tap", "br0", "tap0", "no", "no", 8) + if err != nil { + t.Fatalf("Unexpected error %v", err) + } + q.Shutdown() + <-disconnectedCh +} + +// Checks that the netdev_del command is correctly sent. +// +// We start a QMPLoop, send the netdev_del command and stop the loop. +// +// The netdev_del command should be correctly sent and the QMP loop should +// exit gracefully. +func TestQMPNetdevDel(t *testing.T) { + connectedCh := make(chan *QMPVersion) + disconnectedCh := make(chan struct{}) + buf := newQMPTestCommandBuffer(t) + buf.AddCommand("netdev_del", nil, "return", nil) + cfg := QMPConfig{Logger: qmpTestLogger{}} + q := startQMPLoop(buf, cfg, connectedCh, disconnectedCh) + q.version = checkVersion(t, connectedCh) + err := q.ExecuteNetdevDel(context.Background(), "br0") + if err != nil { + t.Fatalf("Unexpected error %v", err) + } + q.Shutdown() + <-disconnectedCh +} + +func TestQMPNetPCIDeviceAdd(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) + err := q.ExecuteNetPCIDeviceAdd(context.Background(), "br0", "virtio-0", "02:42:ac:11:00:02", "0x7", "") + if err != nil { + t.Fatalf("Unexpected error %v", err) + } + q.Shutdown() + <-disconnectedCh +} + // Checks that the device_add command is correctly sent. // // We start a QMPLoop, send the device_add command and stop the loop.