|
1 | 1 | package qemu
|
2 | 2 |
|
3 | 3 | import (
|
| 4 | + "bytes" |
4 | 5 | "errors"
|
5 | 6 | "fmt"
|
6 | 7 | "os"
|
@@ -136,15 +137,64 @@ func appendArgsIfNoConflict(args []string, k, v string) []string {
|
136 | 137 | }
|
137 | 138 | return append(args, k, v)
|
138 | 139 | }
|
| 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 | + |
139 | 176 | func Cmdline(cfg Config) (string, []string, error) {
|
140 | 177 | y := cfg.LimaYAML
|
141 | 178 | exe, args, err := getExe(y.Arch)
|
142 | 179 | if err != nil {
|
143 | 180 | return "", nil, err
|
144 | 181 | }
|
145 | 182 |
|
| 183 | + features, err := inspectFeatures(exe) |
| 184 | + if err != nil { |
| 185 | + return "", nil, err |
| 186 | + } |
| 187 | + |
146 | 188 | // Architecture
|
147 | 189 | 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 | + } |
148 | 198 | switch y.Arch {
|
149 | 199 | case limayaml.X8664:
|
150 | 200 | // NOTE: "-cpu host" seems to cause kernel panic
|
@@ -202,6 +252,9 @@ func Cmdline(cfg Config) (string, []string, error) {
|
202 | 252 | args = append(args, "-netdev", fmt.Sprintf("user,id=net0,net=%s,dhcpstart=%s,hostfwd=tcp:127.0.0.1:%d-:22",
|
203 | 253 | qemuconst.SlirpNetwork, qemuconst.SlirpIPAddress, y.SSH.LocalPort))
|
204 | 254 | 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 | + } |
205 | 258 | for i, vde := range y.Network.VDE {
|
206 | 259 | // VDE4 accepts VNL like vde:///var/run/vde.ctl as well as file path like /var/run/vde.ctl .
|
207 | 260 | // VDE2 only accepts the latter form.
|
|
0 commit comments