diff --git a/nixos-modules/nixos-host.nix b/nixos-modules/nixos-host.nix index 5bca725..6ab5649 100644 --- a/nixos-modules/nixos-host.nix +++ b/nixos-modules/nixos-host.nix @@ -6,22 +6,29 @@ { options.genodeGuests = with lib; + with lib.types; let genodeOpts = { ... }: { options = { name = mkOption { example = "webserver"; - type = types.str; + type = str; description = "Name of the Genode subsystem."; }; config = mkOption { - type = types.str; - default = ""; + type = oneOf [ str path ]; + example = '' + let Genode = env:DHALL_GENODE + + in Genode.Init::{=} + ''; description = '' - Configuration of the Genode subsystem. - Must be rendered in the Genode XML format. + Configuration of the Genode subsystem in Dhall. + The type of the expression must be Genode.Init.Type, + where the Genode is library available at + env:DHALL_GENODE. ''; }; @@ -39,15 +46,24 @@ ''; }; + nics = mkOption { + type = with types; listOf str; + default = [ ]; + example = [ "tap0" "tap1" ]; + description = '' + TAP interfaces to pass from NixOS into the Genode guest. + ''; + }; + }; }; in mkOption { - type = with lib.types; loaOf (submodule genodeOpts); + type = loaOf (submodule genodeOpts); default = { }; example = { foobar = { - config = ""; + config = "…"; rom = pkgs: { }; }; }; @@ -64,25 +80,38 @@ inherit (crossPkgs.genodePackages) base-linux; toService = name: cfg: { description = "Genode subsystem"; + after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; preStart = let + config' = + self.lib.${crossSystem}.runDhallCommand "${name}.config" { } '' + set -e + exec ${self.apps.${crossSystem}.render-init.program} > $out << EOF + ${./root-config.dhall} + { guest = ${cfg.config} + , nics = [ "${builtins.concatStringsSep ''", "'' cfg.nics}" ] + } + EOF + ''; rom' = with crossPkgs.genodePackages; { - core = "${base-linux}/bin/core-linux"; - init = "${init}/bin/init"; - "ld.lib.so" = "${base-linux}/bin/ld.lib.so"; - timer = "${base-linux}/bin/linux_timer_drv"; - config = builtins.toFile "${name}.config.xml" cfg.config; + init = "${init}/init"; + "ld.lib.so" = "${base-linux}/lib/ld.lib.so"; + timer_drv = "${base-linux}/timer_drv"; + config = config'; + linux_nic_drv = "${ + crossPkgs.genodeSources.depot "linux_nic_drv" + }/linux_nic_drv"; } // (cfg.rom crossPkgs); in builtins.concatStringsSep "\n" - (lib.mapAttrsToList (name: value: "ln -s ${value} ${name}") rom'); + (lib.mapAttrsToList (name: value: "ln -sv ${value} ${name}") rom'); serviceConfig = { DynamicUser = true; RuntimeDirectory = "genode/" + name; WorkingDirectory = "/run/genode/" + name; - ExecStart = "${base-linux}/bin/core-linux"; + ExecStart = "${base-linux}/core-linux"; }; }; in lib.mapAttrs toService config.genodeGuests; diff --git a/nixos-modules/root-config.dhall b/nixos-modules/root-config.dhall new file mode 100644 index 0000000..8a95116 --- /dev/null +++ b/nixos-modules/root-config.dhall @@ -0,0 +1,70 @@ +let Genode = env:DHALL_GENODE + +let Prelude = Genode.Prelude + +let Init = Genode.Init + +let Child = Init.Child + +let nicChild + : Text → Init.Children.Entry + = λ(tapDevice : Text) + → { mapKey = tapDevice + , mapValue = + Child.flat + Child.Attributes::{ + , binary = "linux_nic_drv" + , config = Init.Config::{ attributes = toMap { tap = tapDevice } } + , ld = False + , resources = Init.Resources::{ + , caps = 256 + , ram = Genode.units.MiB 4 + } + , provides = [ "Nic" ] + } + } + +let nicChildren = Prelude.List.map Text Init.Children.Entry nicChild + +let init = + λ(params : { guest : Init.Type, nics : List Text }) + → Init::{ + , routes = [ Init.ServiceRoute.child "Timer" "timer_drv" ] + , children = + nicChildren params.nics + # toMap + { timer_drv = + Child.flat + Child.Attributes::{ + , binary = "timer_drv" + , provides = [ "Timer" ] + } + , init = + Init.toChild + params.guest + Init.Attributes::{ + , exitPropagate = True + , routes = + Prelude.List.map + Text + Init.ServiceRoute.Type + ( λ(tapDevice : Text) + → { service = + { name = "Nic" + , label = Init.LabelSelector.last tapDevice + } + , route = + Init.Route.Type.Child + { name = tapDevice + , label = None Text + , diag = None Bool + } + } + ) + params.nics + } + } + , verbose = True + } + +in init diff --git a/tests/nixos-host.nix b/tests/nixos-host.nix index 6cb744c..7214f02 100644 --- a/tests/nixos-host.nix +++ b/tests/nixos-host.nix @@ -6,45 +6,80 @@ import "${self.inputs.nixpkgs}/nixos/tests/make-test-python.nix" # meta.maintainers = [ pkgs.lib.maintainers.ehmry ]; machine = { + imports = [ self.nixosModules.genodeGuests "${self.inputs.nixpkgs}/nixos/modules/profiles/minimal.nix" ]; - genodeGuests.signal-test = { + + networking.bridges.br0.interfaces = [ "eth0" "tap0" ]; + + networking.interfaces.eth0.useDHCP = false; + + networking.interfaces.tap0 = { + useDHCP = false; + virtual = true; + virtualType = "tap"; + }; + + genodeGuests.tap-test = { config = '' - - - - - - - - - - - - - - - - - - - - + let Genode = env:DHALL_GENODE + + let Prelude = Genode.Prelude + + let XML = Prelude.XML + + let Init = Genode.Init + + in Init::{ + , children = toMap + { lwip_fs = + Init.Child.flat + Init.Child.Attributes::{ + , binary = "vfs" + , config = Init.Config::{ + , content = + [ XML.element + { name = "vfs" + , attributes = XML.emptyAttributes + , content = + [ XML.leaf + { name = "lwip" + , attributes = toMap { dhcp = "yes" } + } + ] + } + ] + } + , provides = [ "File_system" ] + , resources = Init.Resources::{ + , caps = 256 + , ram = Genode.units.MiB 8 + } + , routes = + [ Init.ServiceRoute.parentLabel "Nic" (None Text) (Some "tap0") + , Init.ServiceRoute.parent "Timer" + ] + } + } + , verbose = True + } ''; + nics = [ "tap0" ]; rom = pkgs: { - "test-signal" = - "${pkgs.genodeSources.depot "test-signal"}/bin/test-signal"; + "vfs" = "${pkgs.genodeSources.depot "vfs"}/vfs"; + "libvfs.so" = "${(pkgs.genodeSources.depot "vfs").lib}/lib/libvfs.so"; + "libvfs_lwip.so" = + "${pkgs.genodeSources.depot "vfs_lwip"}/lib/libvfs_lwip.so"; }; }; + }; testScript = '' start_all() - machine.wait_for_unit("genode") + machine.wait_for_unit("tap-test") machine.wait_for_open_port("1965") ''; -}) { - system = localSystem; -} +}) { system = localSystem; }