diff --git a/default.nix b/default.nix index 2e3c73109..216bcd55b 100644 --- a/default.nix +++ b/default.nix @@ -29,6 +29,10 @@ pkgs.python3.pkgs.buildPythonPackage rec { license = pkgs.lib.licenses.asl20; }; + postInstall = '' + install -Dm755 ${create_bridge} $out/bin/${pname}-create-bridge + ''; + nativeCheckInputs = [ pkgs.shellcheck pkgs.pylint diff --git a/nixos-module.nix b/nixos-module.nix new file mode 100644 index 000000000..785b8a666 --- /dev/null +++ b/nixos-module.nix @@ -0,0 +1,50 @@ +# nixos-module.nix +{ config, lib, pkgs, ... }: +let + qemuPkg = config.services.vmrunner.qemuPackage or pkgs.qemu; + vmrunnerPkg = config.services.vmrunner.package or (pkgs.callPackage ./default.nix { }); + + qemuBridgeHelperPath = "/run/wrappers/bin/qemu-bridge-helper"; + bridge = "bridge43"; +in + { + options.services.vmrunner.qemuPackage = lib.mkOption { + type = lib.types.package; + default = pkgs.qemu; + description = "QEMU with capabilities enabled for IncludeOS unikernels"; + }; + + config = { + security.wrappers = { + # https://wiki.qemu.org/Features/HelperNetworking + qemu-bridge-helper = { + source = "${qemuPkg}/libexec/qemu-bridge-helper"; + owner = "root"; + group = "root"; + capabilities = "cap_net_admin+ep"; # required for attaching TAP devices to bridges + }; + + ping = { + source = "${pkgs.iputils}/bin/ping"; + owner = "root"; + group = "root"; + capabilities = "cap_net_raw+ep"; # required to send ICMP packets + }; + }; + + environment = { + etc."qemu/bridge.conf".text = '' + allow ${bridge} + ''; + + systemPackages = [ vmrunnerPkg ]; + + variables.QEMU_BRIDGE_HELPER = qemuBridgeHelperPath; + }; + + networking.firewall = { + trustedInterfaces = [ bridge ]; + }; + }; +} + diff --git a/vmrunner/vmrunner.py b/vmrunner/vmrunner.py index 27237cc1c..04bce9223 100755 --- a/vmrunner/vmrunner.py +++ b/vmrunner/vmrunner.py @@ -471,7 +471,7 @@ def mod_args(self, mods): for mod in mods]) return ["-initrd", mods_list] - def net_arg(self, backend, device, if_name = "net0", mac = None, bridge = None, scripts = None): + def net_arg(self, backend, device, if_name = "net0", mac = None, bridge = None, scripts = None, helper = None): """ creates network argument for hypervisor """ if scripts: qemu_ifup = scripts + "qemu-ifup" @@ -503,6 +503,8 @@ def net_arg(self, backend, device, if_name = "net0", mac = None, bridge = None, if bridge: netdev = "bridge,id=" + if_name + ",br=" + bridge + if helper: + netdev += ",helper=" + helper # Device - e.g. guest side of nic @@ -655,7 +657,8 @@ def boot_in_hypervisor(self, multiboot=True, debug = False, kernel_args = "", im mac = net["mac"] if "mac" in net else None bridge = net["bridge"] if "bridge" in net else None scripts = net["scripts"] if "scripts" in net else None - net_args += self.net_arg(net["backend"], net["device"], "net"+str(i), mac, bridge, scripts) + helper = net.get("helper", os.environ.get("QEMU_BRIDGE_HELPER")) + net_args += self.net_arg(net["backend"], net["device"], "net"+str(i), mac, bridge, scripts, helper) i+=1 mem_arg = []