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 copy
import crypt import crypt
import os import os
import random
import shlex import shlex
import socket 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
@ -48,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()
@ -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, 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',
@ -186,7 +202,7 @@ def parse_args():
ctx.args.save = True ctx.args.save = True
ctx.livefs_editor = os.environ.get('LIVEFS_EDITOR') 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 ' + raise Exception('Obtain a copy of livefs-editor and point ' +
'LIVEFS_EDITOR to it\n' 'LIVEFS_EDITOR to it\n'
'https://github.com/mwhudson/livefs-editor') 'https://github.com/mwhudson/livefs-editor')
@ -339,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 = []
@ -456,21 +508,27 @@ def help():
sys.exit(1) sys.exit(1)
try: def main() -> None:
ctx = parse_args() """ Entry point. """
except TypeError: try:
help() ctx = parse_args()
except TypeError:
help()
if ctx.args.base and ctx.args.build: if ctx.args.base and ctx.args.build:
raise Exception('cannot use base iso and 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: if ctx.args.build:
build(ctx) build(ctx)
if ctx.args.install: if ctx.args.install:
install(ctx) install(ctx)
if ctx.args.boot: if ctx.args.boot:
boot(ctx) boot(ctx)
if True not in (ctx.args.build, ctx.args.install, ctx.args.boot): if True not in (ctx.args.build, ctx.args.install, ctx.args.boot):
parser.print_help() parser.print_help()
if __name__ == "__main__":
main()