{ config, pkgs, lib, ... }: with lib; { options = { networking.interfaces = lib.mkOption { type = with types; attrsOf (submodule ({ ... }: { options.genode = { driver = mkOption { type = types.enum [ "ipxe" "virtio" ]; }; stack = mkOption { type = with types; nullOr (enum [ "lwip" "lxip" ]); default = "lwip"; }; }; })); }; }; config = { assertions = with builtins; let addrCheck = name: interface: { assertion = lessThan (length interface.ipv4.addresses) 2; message = "Genode interfaces do not support multihoming."; }; routeCheck = name: interface: { assertion = lessThan (length interface.ipv4.routes) 2; message = "Genode interfaces do not support multiple routes."; }; policyCheck = name: interface: let clientList = filter (x: x != null) (lib.mapAttrsToList (childName: value: if any (nic: nic == name) value.routeToNics then childName else null) config.genode.init.children); in { assertion = trace clientList (clientList == [ ] || length clientList == 1); message = "Multiple routes to Nic ${name}, ${clientList}"; }; in lib.lists.concatMap (f: lib.mapAttrsToList f config.networking.interfaces) [ addrCheck routeCheck policyCheck ]; hardware.genode.platform.policies = lib.lists.imap0 (i: name: builtins.toFile (name + ".platform-policy.dhall") '' let Genode = env:DHALL_GENODE in Genode.Init.Config.Policy::{ , service = "Platform" , label = Genode.Init.LabelSelector.prefix "${name}.driver" , content = [ Genode.Prelude.XML.leaf { name = "pci" , attributes = toMap { , class = "ETHERNET" , index = "${toString i}" } } ] } '') (builtins.attrNames config.networking.interfaces); genode.core.children = mapAttrs' (name: interface: let name' = name + ".driver"; in { name = name'; value = let binary = with pkgs.genodePackages; { ipxe = ipxe_nic_drv; virtio = virtio_nic_drv; }.${interface.genode.driver}; in { inputs = [ binary ]; configFile = let policy = lib.mapAttrsToList (childName: value: if any (nic: nic == name) value.routeToNics then '' Init.Config.Policy::{ , service = "Nic" , label = Init.LabelSelector.prefix "nixos -> ${childName}" } '' else "") config.genode.init.children; in pkgs.writeText "${name'}.dhall" '' let Genode = env:DHALL_GENODE let Init = Genode.Init in Init.Child.flat Init.Child.Attributes::{ , binary = "${binary.pname}" , provides = [ "Nic" ] , resources = Init.Resources::{ caps = 128, ram = Genode.units.MiB 4 } , routes = [ Init.ServiceRoute.parent "IO_MEM" ] , config = Init.Config::{ , attributes = toMap { verbose = "true" } , policies = [ ${ toString policy } ] : List Init.Config.Policy.Type } } ''; }; }) config.networking.interfaces; genode.init.children = let sockets = mapAttrs' (name: interface: let name' = name + ".sockets"; in { name = name'; value = if interface.genode.stack == null then null else { inputs = with pkgs.genodePackages; { lwip = [ vfs_lwip ]; lxip = [ vfs_lxip ]; }.${interface.genode.stack}; routeToNics = [ name ]; configFile = let binary = "${pkgs.genodePackages.vfs}/bin/vfs"; ram = { lwip = 16; lxip = 32; }.${interface.genode.stack}; settings = with builtins; [{ name = "label"; value = name; }] ++ lib.optionals (interface.ipv4.addresses != [ ]) (let addr = head interface.ipv4.addresses; in [ { name = "ip_addr"; value = addr.address; } { name = "netmask"; value = if addr.prefixLength == 24 then "255.255.255.0" else throw "missing prefix to netmask conversion"; } ]) ++ lib.optional (interface.ipv4.routes != [ ]) (let route = head interface.ipv4.routes; in { name = "gateway"; value = route.address; }) ++ lib.optional (interface.useDHCP != null) { name = "dhcp"; value = if interface.useDHCP then "true" else "false"; }; settingsMap = builtins.concatStringsSep ", " (map ({ name, value }: ''{ mapKey = "${name}", mapValue = "${value}" }'') settings); in pkgs.writeText "${name'}.dhall" '' let Genode = env:DHALL_GENODE let Init = Genode.Init in Init.Child.flat Init.Child.Attributes::{ , binary = "${binary}" , provides = [ "File_system" ] , resources = Init.Resources::{ , caps = 128 , ram = Genode.units.MiB ${toString ram} } , config = Init.Config::{ , policies = [ Init.Config.Policy::{ , service = "File_system" , label = Init.LabelSelector.suffix "${name'}" , attributes = toMap { root = "/", writeable="yes" } } ] , content = let VFS = Genode.VFS in [ VFS.vfs [ VFS.leafAttrs "${interface.genode.stack}" ([ ${settingsMap} ] : Genode.Prelude.Map.Type Text Text) ] ] } } ''; }; }) config.networking.interfaces; in lib.filterAttrs (n: v: v != null) sockets; }; }