Skip to content

Commit

Permalink
[qa] Work around QEMU bug in handling "-set" command-line option
Browse files Browse the repository at this point in the history
Newer versions of QEMU (observed with QEMU 7.2.1 on Fedora 38) seem
not to be able to handle the "-set netdev.hostnet0.bootfile=..."
command-line option that we use to specify the per-test boot URL.  The
error message observed is:

  qemu-system-x86_64: ...: there is no netdev "hostnet0" defined

Adding debug prints to a test build of QEMU shows that at the point
that the "-set" option is handled, the list of netdevs is empty.  This
appears therefore to be a bug in the order of processing command-line
options.  The precise root cause has not been identified, since QEMU's
command-line parsing logic is fairly arcane and relies heavily on
autogenerated code fragments.

Work around the problem by creating a wrapper script that strips the
"-set netdev.hostnet0.bootfile=..." option and instead injects the
bootfile as part of the "-netdev" option found earlier in the same
command line.

(In an ideal world, libvirt would provide a clean way to specify the
bootfile or other options for a "user" network interface, but such a
mechanism does not seem to exist at present.)

Signed-off-by: Michael Brown <[email protected]>
  • Loading branch information
mcb30 committed Aug 14, 2023
1 parent 117038a commit 1a0e600
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 0 deletions.
1 change: 1 addition & 0 deletions test/qemu-system-x86_64
54 changes: 54 additions & 0 deletions test/qemu-wrapper
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/env python3
#
# Work around buggy parsing of "-set" option in newer versions of QEMU

from itertools import pairwise
import json
import re
import os
import sys

# Replace wrapper binary name
#
argv = sys.argv
argv[0] = os.path.basename(argv[0])

# Identify bootfile URL, if specified
#
bootfile = None
bootfileidx = None
for idx, (opt, val) in enumerate(pairwise(argv)):
# Look for "-set netdev.*.bootfile=..."
if opt == '-set':
m = re.fullmatch(r'netdev\..*\.bootfile=(?P<bootfile>.+)', val)
if m:
# Record bootfile and position within argument list
bootfile = m['bootfile']
bootfileidx = idx
break

# Hack bootfile URL into argument list, if applicable
#
# We assume that only versions of QEMU that are sufficiently new to
# handle JSON arguments will have the bug that prevents correct
# parsing of the "-set" option.
#
if bootfile:
for idx, (opt, val) in enumerate(pairwise(argv)):
# Look for "-netdev {json argument}"
if opt == '-netdev':
try:
jval = json.loads(val)
except json.JSONDecodeError:
continue
# Add bootfile to JSON argument
jval['bootfile'] = bootfile
val = json.dumps(jval)
argv[idx + 1] = val
# Strip "-set netdev.*.bootfile=..." from argument list
argv[bootfileidx:(bootfileidx + 2)] = []
break

# Execute real QEMU binary
#
os.execvp(argv[0], argv)
2 changes: 2 additions & 0 deletions test/testwimboot
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ def vm_xml(virttype, name, uuid, memory, uefi, logfile, romfile, booturl):
x_memory.text = str(memory)
x_memory.attrib['unit'] = 'MiB'
x_devices = etree.SubElement(x_domain, 'devices')
x_emulator = etree.SubElement(x_devices, 'emulator')
x_emulator.text = os.path.abspath('qemu-system-x86_64')
x_graphics = etree.SubElement(x_devices, 'graphics')
x_graphics.attrib['type'] = 'spice'
x_video = etree.SubElement(x_devices, 'video')
Expand Down

0 comments on commit 1a0e600

Please sign in to comment.