Skip to content

Commit 004b75a

Browse files
committed
pkg/qemu: check features before starting QEMU
Signed-off-by: Akihiro Suda <[email protected]>
1 parent 460c341 commit 004b75a

File tree

1 file changed

+53
-0
lines changed

1 file changed

+53
-0
lines changed

pkg/qemu/qemu.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package qemu
22

33
import (
4+
"bytes"
45
"errors"
56
"fmt"
67
"os"
@@ -136,15 +137,64 @@ func appendArgsIfNoConflict(args []string, k, v string) []string {
136137
}
137138
return append(args, k, v)
138139
}
140+
141+
type features struct {
142+
// NetdevHelp is the output of `qemu-system-x86_64 -accel help`
143+
// e.g. "Accelerators supported in QEMU binary:\ntcg\nhax\nhvf\n"
144+
// Not machine-readable, but checking strings.Contains() should be fine.
145+
AccelHelp []byte
146+
// NetdevHelp is the output of `qemu-system-x86_64 -netdev help`
147+
// e.g. "Available netdev backend types:\nsocket\nhubport\ntap\nuser\nvde\nbridge\vhost-user\n"
148+
// Not machine-readable, but checking strings.Contains() should be fine.
149+
NetdevHelp []byte
150+
}
151+
152+
func inspectFeatures(exe string) (*features, error) {
153+
var (
154+
f features
155+
stdout bytes.Buffer
156+
stderr bytes.Buffer
157+
)
158+
cmd := exec.Command(exe, "-M", "none", "-accel", "help")
159+
cmd.Stdout = &stdout
160+
cmd.Stderr = &stderr
161+
if err := cmd.Run(); err != nil {
162+
return nil, fmt.Errorf("failed to run %v: stdout=%q, stderr=%q", cmd.Args, stdout.String(), stderr.String())
163+
}
164+
f.AccelHelp = stdout.Bytes()
165+
166+
cmd = exec.Command(exe, "-M", "none", "-netdev", "help")
167+
cmd.Stdout = &stdout
168+
cmd.Stderr = &stderr
169+
if err := cmd.Run(); err != nil {
170+
return nil, fmt.Errorf("failed to run %v: stdout=%q, stderr=%q", cmd.Args, stdout.String(), stderr.String())
171+
}
172+
f.NetdevHelp = stdout.Bytes()
173+
return &f, nil
174+
}
175+
139176
func Cmdline(cfg Config) (string, []string, error) {
140177
y := cfg.LimaYAML
141178
exe, args, err := getExe(y.Arch)
142179
if err != nil {
143180
return "", nil, err
144181
}
145182

183+
features, err := inspectFeatures(exe)
184+
if err != nil {
185+
return "", nil, err
186+
}
187+
146188
// Architecture
147189
accel := getAccel(y.Arch)
190+
if !strings.Contains(string(features.AccelHelp), accel) {
191+
errStr := fmt.Sprintf("accelerator %q is not supported by %s", accel, exe)
192+
if accel == "hvf" && y.Arch == limayaml.AARCH64 {
193+
errStr += " ( Hint: as of August 2021, qemu-system-aarch64 on ARM Mac needs to be patched for enabling hvf accelerator,"
194+
errStr += " see https://gist.github.com/nrjdalal/e70249bb5d2e9d844cc203fd11f74c55 )"
195+
}
196+
return "", nil, errors.New(errStr)
197+
}
148198
switch y.Arch {
149199
case limayaml.X8664:
150200
// NOTE: "-cpu host" seems to cause kernel panic
@@ -202,6 +252,9 @@ func Cmdline(cfg Config) (string, []string, error) {
202252
args = append(args, "-netdev", fmt.Sprintf("user,id=net0,net=%s,dhcpstart=%s,hostfwd=tcp:127.0.0.1:%d-:22",
203253
qemuconst.SlirpNetwork, qemuconst.SlirpIPAddress, y.SSH.LocalPort))
204254
args = append(args, "-device", "virtio-net-pci,netdev=net0,mac="+limayaml.MACAddress(cfg.InstanceDir))
255+
if len(y.Network.VDE) > 0 && !strings.Contains(string(features.NetdevHelp), "vde") {
256+
return "", nil, fmt.Errorf("netdev \"vde\" is not supported by %s ( Hint: recompile QEMU with `configure --enable-vde` )", exe)
257+
}
205258
for i, vde := range y.Network.VDE {
206259
// VDE4 accepts VNL like vde:///var/run/vde.ctl as well as file path like /var/run/vde.ctl .
207260
// VDE2 only accepts the latter form.

0 commit comments

Comments
 (0)