Merge pull request #1286 from ogayot/tap-network

Add ability to pass custom -nic options to QEMU
This commit is contained in:
Olivier Gayot 2022-04-28 19:14:46 +02:00 committed by GitHub
commit 0267f7d66f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 91 additions and 33 deletions

View File

@ -14,13 +14,12 @@ import contextlib
import copy
import crypt
import os
import random
import shlex
import socket
import subprocess
import sys
import tempfile
from typing import Tuple
from typing import List, Tuple
import yaml
@ -48,6 +47,11 @@ def salted_crypt(plaintext_password):
return crypt.crypt(plaintext_password, salt)
class Tap:
def __init__(self, ifname: str) -> None:
self.ifname = ifname
class Context:
def __init__(self, args):
self.config = self.load_config()
@ -150,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,
help='''number of network interfaces.
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',
help='allow overwrite of the target image')
parser.add_argument('-q', '--quick', default=False, action='store_true',
@ -186,7 +202,7 @@ def parse_args():
ctx.args.save = True
ctx.livefs_editor = os.environ.get('LIVEFS_EDITOR')
if not ctx.livefs_editor:
if not ctx.livefs_editor and ctx.args.build:
raise Exception('Obtain a copy of livefs-editor and point ' +
'LIVEFS_EDITOR to it\n'
'https://github.com/mwhudson/livefs-editor')
@ -339,23 +355,59 @@ class PortFinder:
return next(self.finder)
def nets(ctx):
if ctx.args.nets > 0:
ports = PortFinder()
ret = []
for _ in range(ctx.args.nets):
port = ports.get()
ret.extend(('-nic',
'user,model=virtio-net-pci,' +
f'hostfwd=tcp::{port}-:22'))
return ret
elif ctx.args.nets == 0:
# no network
return ('-nic', 'none')
else:
# nic present but restricted - simulate deadnet environment
class NetFactory:
""" Generate -nic options for QEMU. """
ports_finder = PortFinder()
def user(self) -> Tuple[str, ...]:
""" User host network with SSH forwarding """
port = self.ports_finder.get()
return ('-nic', f'user,model=virtio-net-pci,hostfwd=tcp::{port}-:22')
def tap(self, ifname: str) -> Tuple[str, ...]:
""" Network using an existing TAP interface. """
tap_props = {
"id": ifname,
"ifname": ifname,
"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')
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):
ret = []
@ -456,21 +508,27 @@ def help():
sys.exit(1)
try:
ctx = parse_args()
except TypeError:
help()
def main() -> None:
""" Entry point. """
try:
ctx = parse_args()
except TypeError:
help()
if ctx.args.base and ctx.args.build:
raise Exception('cannot use base iso and build')
if ctx.args.base and ctx.args.build:
raise Exception('cannot use base iso and build')
os.makedirs('/tmp/kvm-test', exist_ok=True)
os.makedirs('/tmp/kvm-test', exist_ok=True)
if ctx.args.build:
build(ctx)
if ctx.args.install:
install(ctx)
if ctx.args.boot:
boot(ctx)
if True not in (ctx.args.build, ctx.args.install, ctx.args.boot):
parser.print_help()
if ctx.args.build:
build(ctx)
if ctx.args.install:
install(ctx)
if ctx.args.boot:
boot(ctx)
if True not in (ctx.args.build, ctx.args.install, ctx.args.boot):
parser.print_help()
if __name__ == "__main__":
main()