kvm-test: introduce ability to pass -nic options to QEMU
The only way we had to pass -nic options to QEMU was to specify the number of networks using the --nets option. Depending on its value, the option would instruct QEMU to: * instantiate *n* user host networks if --nets >= 1 * instantiate no network if --nets is 0 * instantiate a "dead" network if --nets < 0 To simulate more advanced networks (such as networks where HTTP proxy is needed), we want to add the possibility to use TAP network interfaces. This patch adds the ability to pass custom -nic options to QEMU. Three new options are available: * The --nic option passes the argument as-is to QEMU -nic option * The --nic-user option passes a user host network -nic option to QEMU - with SSH forwarding enabled. This is just like we do when using the --nets >= 1 option) * The --net-tap takes the name of an existing tap interface and generates the following -nic argument: tap,id={ifname},ifname={ifname},script=no,downscript=no,model=e1000 In the example below: * the first network uses the tap0 interface. * the second network uses the tap1 interface (it is syntactically equivalent to the first one) * the third network uses a user host network (with SSH forwarding) $ kvm-test.py \ --nic tap,id=tap0,ifname=tap0,script=no,downscript=no,model=e1000 \ --nic-tap tap1 \ --nic-user Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
This commit is contained in:
parent
eb7dee2c9e
commit
e58d1d00c2
|
@ -19,7 +19,7 @@ import socket
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
from typing import Tuple
|
from typing import List, Tuple
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
|
@ -47,6 +47,11 @@ def salted_crypt(plaintext_password):
|
||||||
return crypt.crypt(plaintext_password, salt)
|
return crypt.crypt(plaintext_password, salt)
|
||||||
|
|
||||||
|
|
||||||
|
class Tap:
|
||||||
|
def __init__(self, ifname: str) -> None:
|
||||||
|
self.ifname = ifname
|
||||||
|
|
||||||
|
|
||||||
class Context:
|
class Context:
|
||||||
def __init__(self, args):
|
def __init__(self, args):
|
||||||
self.config = self.load_config()
|
self.config = self.load_config()
|
||||||
|
@ -149,6 +154,18 @@ parser.add_argument('-i', '--img', action='store', help='use this img')
|
||||||
parser.add_argument('-n', '--nets', action='store', default=1, type=int,
|
parser.add_argument('-n', '--nets', action='store', default=1, type=int,
|
||||||
help='''number of network interfaces.
|
help='''number of network interfaces.
|
||||||
0=no network, -1=deadnet''')
|
0=no network, -1=deadnet''')
|
||||||
|
parser.add_argument('--nic-user', action="append_const", dest="nics",
|
||||||
|
const=None,
|
||||||
|
help='pass user host -nic to QEMU'
|
||||||
|
' - overrides --nets')
|
||||||
|
parser.add_argument('--nic-tap', action="append", dest="nics", type=Tap,
|
||||||
|
metavar="ifname",
|
||||||
|
help='TAP interface to be passed as -nic to QEMU'
|
||||||
|
' - overrides --nets')
|
||||||
|
parser.add_argument('--nic', action="append", dest="nics",
|
||||||
|
metavar="argument",
|
||||||
|
help='pass custom -nic argument to QEMU'
|
||||||
|
' - overrides --nets')
|
||||||
parser.add_argument('-o', '--overwrite', default=False, action='store_true',
|
parser.add_argument('-o', '--overwrite', default=False, action='store_true',
|
||||||
help='allow overwrite of the target image')
|
help='allow overwrite of the target image')
|
||||||
parser.add_argument('-q', '--quick', default=False, action='store_true',
|
parser.add_argument('-q', '--quick', default=False, action='store_true',
|
||||||
|
@ -338,23 +355,59 @@ class PortFinder:
|
||||||
return next(self.finder)
|
return next(self.finder)
|
||||||
|
|
||||||
|
|
||||||
def nets(ctx):
|
class NetFactory:
|
||||||
if ctx.args.nets > 0:
|
""" Generate -nic options for QEMU. """
|
||||||
ports = PortFinder()
|
ports_finder = PortFinder()
|
||||||
ret = []
|
|
||||||
for _ in range(ctx.args.nets):
|
def user(self) -> Tuple[str, ...]:
|
||||||
port = ports.get()
|
""" User host network with SSH forwarding """
|
||||||
ret.extend(('-nic',
|
port = self.ports_finder.get()
|
||||||
'user,model=virtio-net-pci,' +
|
return ('-nic', f'user,model=virtio-net-pci,hostfwd=tcp::{port}-:22')
|
||||||
f'hostfwd=tcp::{port}-:22'))
|
|
||||||
return ret
|
def tap(self, ifname: str) -> Tuple[str, ...]:
|
||||||
elif ctx.args.nets == 0:
|
""" Network using an existing TAP interface. """
|
||||||
# no network
|
tap_props = {
|
||||||
return ('-nic', 'none')
|
"id": ifname,
|
||||||
else:
|
"ifname": ifname,
|
||||||
# nic present but restricted - simulate deadnet environment
|
"script": "no",
|
||||||
|
"downscript": "no",
|
||||||
|
"model": "e1000",
|
||||||
|
}
|
||||||
|
|
||||||
|
nic = ",".join(["tap"] + [f"{k}={v}" for k, v in tap_props.items()])
|
||||||
|
|
||||||
|
return ('-nic', nic)
|
||||||
|
|
||||||
|
def deadnet(self) -> Tuple[str, ...]:
|
||||||
|
""" NIC present but restricted - simulate deadnet environment """
|
||||||
return ('-nic', 'user,model=virtio-net-pci,restrict=on')
|
return ('-nic', 'user,model=virtio-net-pci,restrict=on')
|
||||||
|
|
||||||
|
def nonet(self) -> Tuple[str, ...]:
|
||||||
|
""" No network """
|
||||||
|
return ('-nic', 'none')
|
||||||
|
|
||||||
|
|
||||||
|
def nets(ctx) -> List[str]:
|
||||||
|
nics: List[str] = []
|
||||||
|
factory = NetFactory()
|
||||||
|
|
||||||
|
if ctx.args.nics:
|
||||||
|
for nic in ctx.args.nics:
|
||||||
|
if nic is None:
|
||||||
|
nics.extend(factory.user())
|
||||||
|
elif isinstance(nic, Tap):
|
||||||
|
nics.extend(factory.tap(nic.ifname))
|
||||||
|
else:
|
||||||
|
nics.extend(('-nic', nic))
|
||||||
|
elif ctx.args.nets > 0:
|
||||||
|
for _ in range(ctx.args.nets):
|
||||||
|
nics.extend(factory.user())
|
||||||
|
elif ctx.args.nets == 0:
|
||||||
|
nics.extend(factory.nonet())
|
||||||
|
else:
|
||||||
|
nics.extend(factory.deadnet())
|
||||||
|
return nics
|
||||||
|
|
||||||
|
|
||||||
def bios(ctx):
|
def bios(ctx):
|
||||||
ret = []
|
ret = []
|
||||||
|
|
Loading…
Reference in New Issue