From b951c22a0d1ef1de258f371af2b499a96c37ef05 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Tue, 3 Nov 2020 19:21:10 +0100 Subject: [PATCH] Refactor routing Patch init to simplify routing. Update Dhall library and NixOS modules accordingly. --- nixos-modules/genode-core.nix | 41 +- nixos-modules/genode-init.nix | 71 ++-- nixos-modules/store-wrapper.dhall | 200 ++++++---- packages/dhall/genode.nix | 6 +- packages/genodelabs/sandbox.patch | 623 ++++++++++++++++++++++++++---- tests/hello.nix | 3 +- tests/solo5/net_2if.dhall | 4 +- 7 files changed, 743 insertions(+), 205 deletions(-) diff --git a/nixos-modules/genode-core.nix b/nixos-modules/genode-core.nix index 3cf5fc3..aae9149 100644 --- a/nixos-modules/genode-core.nix +++ b/nixos-modules/genode-core.nix @@ -57,7 +57,6 @@ in { }; config = let - initInputs = unique config.genode.init.inputs; addManifest = drv: drv // { @@ -91,6 +90,12 @@ in { in (foldl' f "[" inputs) + "]"; }; + romDirectories = mapAttrs (name: value: + pkgs.symlinkJoin { + name = "${name}-rom"; + paths = value.inputs; + }) config.genode.init.children; + in { assertions = [{ @@ -104,38 +109,31 @@ in { "${config.system.build.tarball}/tarball/${config.system.build.tarball.fileName}.tar"; manifest = mergeManifests (map addManifest (config.genode.core.basePackages ++ [ config.system.build.tarball ] - ++ (with pkgs.genodePackages; [ init cached_fs_rom vfs ]))); + ++ (with pkgs.genodePackages; [ init cached_fs_rom vfs ]))); + storeRomPolicies = let + policies = mapAttrsToList + (name: value: '', { mapKey = "${name}", mapValue = "${value}" }'') + romDirectories; + in "[${toString policies}]"; in localPackages.runCommand "boot.dhall" { } '' cat > $out << EOF ${./store-wrapper.dhall} (${config.genode.init.configFile}) "${config.system.build.tarball.fileName}.tar" $(stat --format '%s' ${tarball}) - ${config.system.build.storeManifest} ${manifest} + ${storeRomPolicies} + ${manifest} EOF ''; - system.build.storeManifest = mergeManifests (map addManifest initInputs); - # Create the tarball of the store to live in core ROM system.build.tarball = pkgs.callPackage "${modulesPath}/../lib/make-system-tarball.nix" { contents = [ ]; - storeContents = [ - { - # assume that the init config will depend - # on every store path needed to boot - object = config.genode.init.configFile; - symlink = "/config.dhall"; - } - { - object = pkgs.buildPackages.symlinkJoin { - name = config.system.name + ".rom"; - paths = config.genode.init.inputs; - }; - symlink = "/rom"; - } - ]; + storeContents = mapAttrsToList (name: object: { + symlink = "rom/${name}"; + inherit object; + }) romDirectories; compressCommand = "cat"; compressionExtension = ""; }; @@ -143,13 +141,12 @@ in { system.build.initXml = pkgs.buildPackages.runCommand "init.xml" { nativeBuildInputs = with pkgs.buildPackages; [ dhall xorg.lndir ]; DHALL_GENODE = "${pkgs.genodePackages.dhallGenode}/binary.dhall"; - BOOT_CONFIG = config.genode.boot.configFile; } '' export XDG_CACHE_HOME=$NIX_BUILD_TOP lndir -silent \ ${pkgs.genodePackages.dhallGenode}/.cache \ $XDG_CACHE_HOME - dhall text <<< "(env:DHALL_GENODE).Init.render (env:BOOT_CONFIG).config" > $out + dhall text <<< "(env:DHALL_GENODE).Init.render (${config.genode.boot.configFile}).config" > $out ''; }; diff --git a/nixos-modules/genode-init.nix b/nixos-modules/genode-init.nix index c6c97a0..6bd4235 100644 --- a/nixos-modules/genode-init.nix +++ b/nixos-modules/genode-init.nix @@ -3,6 +3,7 @@ with lib; let + cfg = config.genode.init; inputs = mkOption { description = "List of packages to build a ROM store with."; type = types.listOf types.package; @@ -10,7 +11,6 @@ let in { options.genode.init = { - inherit inputs; configFile = mkOption { description = '' @@ -56,54 +56,51 @@ in { }); }; - subinits = mkOption { - default = { }; - type = with types; - attrsOf (submodule { - options = { - inherit inputs; - configFile = mkOption { - type = types.path; - description = '' - Dhall configuration of child init. - See https://git.sr.ht/~ehmry/dhall-genode/tree/master/Init/Type - ''; + subinits = + # Subinits are just a different kind of children. + # Eventually this will be nested "genode.init" instances. + mkOption { + default = { }; + type = with types; + attrsOf (submodule { + options = { + inherit inputs; + configFile = mkOption { + type = types.path; + description = '' + Dhall configuration of child init. + See https://git.sr.ht/~ehmry/dhall-genode/tree/master/Init/Type + ''; + }; }; - }; - }); - }; + }); + }; }; - config = { - - genode.init.inputs = with builtins; - [ pkgs.genodePackages.report_rom ] ++ concatLists (catAttrs "inputs" - ((attrValues config.genode.init.children) - ++ (attrValues config.genode.init.subinits))); + config.genode.init = { # TODO: convert the subinits to children - genode.init.configFile = pkgs.writeText "init.dhall" '' + children = mapAttrs (name: value: { + inherit (value) inputs; + configFile = pkgs.writeText "${name}.child.dhall" '' + let Genode = env:DHALL_GENODE + + in Genode.Init.toChild ${value.configFile} Genode.Init.Attributes.default + ''; + }) cfg.subinits; + + configFile = pkgs.writeText "init.dhall" '' let Genode = env:DHALL_GENODE - let baseConfig = ${config.genode.init.baseConfig} + let baseConfig = ${cfg.baseConfig} in baseConfig with children = baseConfig.children # toMap {${ concatMapStrings (name: ", `${name}` = (${ - config.genode.init.children.${name}.configFile - } : Genode.Init.Child.Type)") - (builtins.attrNames config.genode.init.children) - } ${ - concatMapStrings (name: '' - , `${name}` = - Genode.Init.toChild - (${ - config.genode.init.subinits.${name}.configFile - } : Genode.Init.Type) - Genode.Init.Attributes.default - '') (builtins.attrNames config.genode.init.subinits) - } } + cfg.children.${name}.configFile + } : Genode.Init.Child.Type) }") (builtins.attrNames cfg.children) + } ''; }; diff --git a/nixos-modules/store-wrapper.dhall b/nixos-modules/store-wrapper.dhall index 1922540..6b5cb2d 100644 --- a/nixos-modules/store-wrapper.dhall +++ b/nixos-modules/store-wrapper.dhall @@ -1,5 +1,4 @@ -let Genode = - env:DHALL_GENODE sha256:e90438be23b5100003cf018b783986df67bc6d0e3d35e800677d0d9109ff6aa9 +let Genode = env:DHALL_GENODE let Prelude = Genode.Prelude @@ -13,75 +12,48 @@ let TextMapType = Prelude.Map.Type Text let Manifest/Type = TextMapType (TextMapType Text) -let Manifest/toRoutes = - λ(manifest : Manifest/Type) → - Prelude.List.map - (Prelude.Map.Entry Text Text) - Init.ServiceRoute.Type - ( λ(entry : Prelude.Map.Entry Text Text) → - { service = - { name = "ROM" - , label = Init.LabelSelector.Type.Last entry.mapKey - } - , route = - Init.Route.Type.Child - { name = "store_rom" - , label = Some entry.mapValue - , diag = Some True - } - } - ) - ( Prelude.List.concat - (Prelude.Map.Entry Text Text) - (Prelude.Map.values Text (Prelude.Map.Type Text Text) manifest) - ) +let storeServiceRoute = + { service = + { name = "ROM", label = Init.LabelSelector.prefix "/nix/store/" } + , route = + Init.Route.Type.Parent + { prefix = Some "", suffix = None Text, diag = Some True } + } -let parentROMs = - Prelude.List.map - Text - Init.ServiceRoute.Type - ( λ(label : Text) → - { service = { name = "ROM", label = Init.LabelSelector.last label } - , route = - Init.Route.Type.Parent { label = Some label, diag = None Bool } - } - ) +let withStoreRoute = + λ(attrs : Child.Attributes.Type) → + attrs + with routes = attrs.routes # [ storeServiceRoute ] -let wrapStore - : Init.Type → Manifest/Type → Child.Type - = λ(init : Init.Type) → - λ(manifest : Manifest/Type) → - Init.toChild - init - Init.Attributes::{ - , exitPropagate = True - , resources = Init.Resources::{ ram = Genode.units.MiB 4 } - , routes = - [ Init.ServiceRoute.parent "IO_MEM" - , Init.ServiceRoute.parent "IO_PORT" - , Init.ServiceRoute.parent "IRQ" - , Init.ServiceRoute.parent "VM" - , Init.ServiceRoute.child "Timer" "timer" - , Init.ServiceRoute.child "Rtc" "rtc" - ] - # parentROMs - [ "ld.lib.so" - , "init" - , "platform_info" - , "core_log" - , "kernel_log" - , "vfs" - , "vfs.lib.so" - , "cached_fs_rom" - ] - # Manifest/toRoutes manifest - # [ Init.ServiceRoute.child "ROM" "store_rom" ] +let Child/withStoreRoutes + : Child.Type → Child.Type + = λ(child : Child.Type) → + child + Child.Type + { flat = + λ(attrs : Child.Attributes.Type) → + Child.flat (withStoreRoute attrs) + , nested = + λ(children : Prelude.Map.Type Text Child.Type) → + λ(attrs : Child.Attributes.Type) → + Child.nested children (withStoreRoute attrs) } +let Init/withStoreRoutes = + λ(init : Init.Type) → + init + with children = + Prelude.Map.map + Text + Child.Type + Child.Type + Child/withStoreRoutes + init.children + in λ(subinit : Init.Type) → λ(storeName : Text) → λ(storeSize : Natural) → - λ(storeManifest : Manifest/Type) → + λ(storeRomPolicies : Prelude.Map.Type Text Text) → λ(bootManifest : Manifest/Type) → Genode.Boot::{ , config = Init::{ @@ -148,9 +120,107 @@ in λ(subinit : Init.Type) → , resources = Init.Resources::{ , ram = storeSize + Genode.units.MiB 1 } + , config = Init.Config::{ + , policies = + [ Init.Config.Policy::{ + , service = "ROM" + , label = + Init.LabelSelector.prefix + "nixos -> /nix/store" + } + ] + # ( let Entry = Prelude.Map.Entry Text Text + + in Prelude.List.concatMap + Entry + Init.Config.Policy.Type + ( λ(e : Entry) → + [ Init.Config.Policy::{ + , service = "ROM" + , label = + Init.LabelSelector.prefix + "nixos -> ${e.mapKey}" + , attributes = toMap + { directory = + "${e.mapValue}/bin" + } + } + , Init.Config.Policy::{ + , service = "ROM" + , label = + Init.LabelSelector.Type.Partial + { prefix = Some + "nixos -> ${e.mapKey}" + , suffix = Some ".lib.so" + } + , attributes = toMap + { directory = + "${e.mapValue}/lib" + } + } + ] + ) + storeRomPolicies + ) + } + } + ) + , child + "nixos" + ( Init.toChild + (Init/withStoreRoutes subinit) + Init.Attributes::{ + , exitPropagate = True + , resources = Init.Resources::{ + , ram = Genode.units.MiB 4 + } + , routes = + let parentROMs = + Prelude.List.concatMap + Text + Init.ServiceRoute.Type + ( λ(suffix : Text) → + Prelude.List.map + Text + Init.ServiceRoute.Type + ( λ(prefix : Text) → + { service = + { name = "ROM" + , label = + Init.LabelSelector.Type.Partial + { prefix = Some prefix + , suffix = Some suffix + } + } + , route = + Init.Route.parent + (Some suffix) + } + ) + ( Prelude.Map.keys + Text + Init.Child.Type + subinit.children + ) + ) + + in parentROMs + [ "ld.lib.so" + , "vfs.lib.so" + , "init" + , "platform_info" + , "core_log" + , "kernel_log" + ] + # [ Init.ServiceRoute.parent "IO_MEM" + , Init.ServiceRoute.parent "IO_PORT" + , Init.ServiceRoute.parent "IRQ" + , Init.ServiceRoute.parent "VM" + , Init.ServiceRoute.child "Timer" "timer" + , Init.ServiceRoute.child "Rtc" "rtc" + ] } ) - , child "init" (wrapStore subinit storeManifest) ] } , rom = diff --git a/packages/dhall/genode.nix b/packages/dhall/genode.nix index 62a4ee5..69a59b2 100644 --- a/packages/dhall/genode.nix +++ b/packages/dhall/genode.nix @@ -6,12 +6,12 @@ dhallPackages.buildDhallPackage { code = let src = fetchgit { url = "https://git.sr.ht/~ehmry/dhall-genode"; - rev = "1a6b3609a778f1644bc2831c366c65cce854ae42"; - sha256 = "1zcnja7wmjx8rlm38x0lkgdz7cfwnd4m6jkasczrf7jqr53j73kv"; + rev = "dd8fc181d56389cf65ae4d2d628fd20c3e0a7981"; + sha256 = "1bmly5jlpgl4r385ykmjkng4dzwcalh5cr25cnk2l16s8ysqwdsl"; }; in src + "/package.dhall"; - dependencies = [ dhallPackages.Prelude."13.0.0" ]; + dependencies = [ dhallPackages.Prelude ]; source = true; } diff --git a/packages/genodelabs/sandbox.patch b/packages/genodelabs/sandbox.patch index 050dd42..6422003 100644 --- a/packages/genodelabs/sandbox.patch +++ b/packages/genodelabs/sandbox.patch @@ -1,84 +1,37 @@ -commit 20abcefd185d72ecc55e87ff78f8f784d927653d -Author: Emery Hemingway -Date: Sat Apr 25 16:08:45 2020 +0530 +From dc4594b0bb0effdd261c70147a47ff0f0b8ee1f3 Mon Sep 17 00:00:00 2001 +From: Emery Hemingway +Date: Sat, 25 Apr 2020 17:10:03 +0530 +Subject: [PATCH 1/3] init/sandbox: support - Init/sandbox: always route "ld.lib.so" ROM to parent - - A livelock may occur if init router the "ld.lib.so" ROM request of a - child to another child, and the child providing the ROM interacts with - Init during the creation of the session. +Apply routing rules to a child from a node at the top-level of +a sandbox config, unless the corresponding start node has as +node. If neither are present routes are taken from as a +fallback. + +Unlike the and the rules are checked by +labels prefixed by child name, so may contain child-specific +rules. +--- + repos/os/src/lib/sandbox/child.cc | 12 +++++++++++- + repos/os/src/lib/sandbox/child.h | 10 ++++++++++ + repos/os/src/lib/sandbox/library.cc | 14 +++++++++++++- + repos/os/src/lib/sandbox/utils.h | 8 +++++--- + 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/repos/os/src/lib/sandbox/child.cc b/repos/os/src/lib/sandbox/child.cc -index 5361665eac..fa09cca31a 100644 +index e321df61fd..d25e3d9683 100644 --- a/repos/os/src/lib/sandbox/child.cc +++ b/repos/os/src/lib/sandbox/child.cc -@@ -448,6 +448,8 @@ Sandbox::Child::Route - Sandbox::Child::resolve_session_request(Service::Name const &service_name, - Session_label const &label) - { -+ auto no_filter = [] (Service &) -> bool { return false; }; -+ - /* check for "config" ROM request */ - if (service_name == Rom_session::service_name() && - label.last_element() == "config") { -@@ -498,9 +500,20 @@ Sandbox::Child::resolve_session_request(Service::Name const &service_name, - label == _unique_name && _unique_name != _binary_name) - return resolve_session_request(service_name, _binary_name); - -- /* supply binary as dynamic linker if '' */ -- if (!_use_ld && service_name == Rom_session::service_name() && label == "ld.lib.so") -- return resolve_session_request(service_name, _binary_name); -+ /* -+ * Check for the "ld.lib.so" ROM request -+ */ -+ if (service_name == Rom_session::service_name() && label == "ld.lib.so") { -+ if (_use_ld) { -+ /* forward request to parent */ -+ return Route { -+ find_service(_parent_services, Rom_session::service_name(), no_filter), -+ Session_label("ld.lib.so"), Session::Diag { false} }; -+ } else { -+ /* supply binary as dynamic linker if '' */ -+ return resolve_session_request(service_name, _binary_name); -+ } -+ } - - /* check for "session_requests" ROM request */ - if (service_name == Rom_session::service_name() -@@ -541,8 +554,6 @@ Sandbox::Child::resolve_session_request(Service::Name const &service_name, - Session::Diag const - target_diag { target.attribute_value("diag", false) }; - -- auto no_filter = [] (Service &) -> bool { return false; }; -- - if (target.has_type("parent")) { - - try { -commit ce74d9bb7740f14b362e72adcf8ac42e36693468 -Author: Emery Hemingway -Date: Sat Apr 25 17:10:03 2020 +0530 - - init/sandbox: support - - Apply routing rules to a child from a node at the top-level of - a sandbox config, unless the corresponding start node has as - node. If neither are present routes are taken from as a - fallback. - - Unlike the and the rules are checked by - labels prefixed by child name, so may contain child-specific - rules. - -diff --git a/repos/os/src/lib/sandbox/child.cc b/repos/os/src/lib/sandbox/child.cc -index fa09cca31a..85389474ef 100644 ---- a/repos/os/src/lib/sandbox/child.cc -+++ b/repos/os/src/lib/sandbox/child.cc -@@ -523,16 +523,21 @@ Sandbox::Child::resolve_session_request(Service::Name const &service_name, +@@ -487,17 +487,25 @@ Sandbox::Child::resolve_session_request(Service::Name const &service_name, + Session::Label(), Session::Diag{false} }; try { ++ /* Lookup route in … */ Xml_node route_node = _default_route_accessor.default_route(); ++ /* …unless is present… */ + route_node = _routes_accessor.routes(route_node); try { ++ /* …otherwise use . */ route_node = _start_node->xml().sub_node("route"); } catch (...) { } + @@ -96,7 +49,7 @@ index fa09cca31a..85389474ef 100644 continue; Xml_node target = service_node.sub_node(); -@@ -736,6 +741,7 @@ Sandbox::Child::Child(Env &env, +@@ -705,6 +713,7 @@ Sandbox::Child::Child(Env &env, Report_update_trigger &report_update_trigger, Xml_node start_node, Default_route_accessor &default_route_accessor, @@ -104,7 +57,7 @@ index fa09cca31a..85389474ef 100644 Default_caps_accessor &default_caps_accessor, Name_registry &name_registry, Ram_quota ram_limit, -@@ -753,6 +759,7 @@ Sandbox::Child::Child(Env &env, +@@ -722,6 +731,7 @@ Sandbox::Child::Child(Env &env, _list_element(this), _start_node(_alloc, start_node), _default_route_accessor(default_route_accessor), @@ -113,7 +66,7 @@ index fa09cca31a..85389474ef 100644 _ram_limit_accessor(ram_limit_accessor), _cap_limit_accessor(cap_limit_accessor), diff --git a/repos/os/src/lib/sandbox/child.h b/repos/os/src/lib/sandbox/child.h -index 4dd2803417..8e84e9bf75 100644 +index 2c213e662c..81836a2045 100644 --- a/repos/os/src/lib/sandbox/child.h +++ b/repos/os/src/lib/sandbox/child.h @@ -52,6 +52,14 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup @@ -139,7 +92,7 @@ index 4dd2803417..8e84e9bf75 100644 Default_caps_accessor &_default_caps_accessor; Ram_limit_accessor &_ram_limit_accessor; Cap_limit_accessor &_cap_limit_accessor; -@@ -475,6 +484,7 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup +@@ -473,6 +482,7 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup Report_update_trigger &report_update_trigger, Xml_node start_node, Default_route_accessor &default_route_accessor, @@ -226,3 +179,523 @@ index 7afcaebf00..36aab737f2 100644 if (!scoped_label) return false; +-- +2.28.0 + + +From 13f2b3357f0e366a61d8b440fb56a52e5d2dfaff Mon Sep 17 00:00:00 2001 +From: Emery Hemingway +Date: Wed, 4 Nov 2020 11:03:49 +0100 +Subject: [PATCH 2/3] init/sandbox: do not parse if + is present + +--- + repos/os/src/lib/sandbox/library.cc | 124 +++++++++++++++++++--------- + 1 file changed, 85 insertions(+), 39 deletions(-) + +diff --git a/repos/os/src/lib/sandbox/library.cc b/repos/os/src/lib/sandbox/library.cc +index 30d0f2dfc1..caa9840ea6 100644 +--- a/repos/os/src/lib/sandbox/library.cc ++++ b/repos/os/src/lib/sandbox/library.cc +@@ -184,47 +184,93 @@ struct Genode::Sandbox::Library : ::Sandbox::State_reporter::Producer, + + void Genode::Sandbox::Library::_update_parent_services_from_config(Xml_node const &config) + { +- Xml_node const node = config.has_sub_node("parent-provides") +- ? config.sub_node("parent-provides") +- : Xml_node(""); +- +- /* remove services that are no longer present in config */ +- _parent_services.for_each([&] (Parent_service &service) { +- +- Service::Name const name = service.name(); +- +- bool obsolete = true; ++ if (config.has_sub_node("routes")) { ++ if (config.has_sub_node("parent-provides")) ++ warning("ignoring and parsing instead"); ++ ++ Xml_node const node = config.sub_node("routes"); ++ ++ /* remove services that are no longer present in config */ ++ _parent_services.for_each([&] (Parent_service &service) { ++ ++ Service::Name const name = service.name(); ++ ++ bool obsolete = true; ++ node.for_each_sub_node("service", [&] (Xml_node service) { ++ if (obsolete && name == service.attribute_value("name", Service::Name())) { ++ obsolete = !service.has_sub_node("parent"); }}); ++ ++ if (obsolete) ++ service.abandon(); ++ }); ++ ++ /* used to prepend the list of new parent services with title */ ++ bool first_log = true; ++ ++ /* register new services */ + node.for_each_sub_node("service", [&] (Xml_node service) { +- if (name == service.attribute_value("name", Service::Name())) { +- obsolete = false; }}); +- +- if (obsolete) +- service.abandon(); +- }); +- +- /* used to prepend the list of new parent services with title */ +- bool first_log = true; +- +- /* register new services */ +- node.for_each_sub_node("service", [&] (Xml_node service) { +- +- Service::Name const name = service.attribute_value("name", Service::Name()); +- +- bool registered = false; +- _parent_services.for_each([&] (Parent_service const &service) { +- if (service.name() == name) +- registered = true; }); +- +- if (!registered) { +- new (_heap) ::Sandbox::Parent_service(_parent_services, _env, name); +- if (_verbose->enabled()) { +- if (first_log) +- log("parent provides"); +- log(" service \"", name, "\""); +- first_log = false; ++ if (service.has_sub_node("child")) return; ++ ++ Service::Name const name = service.attribute_value("name", Service::Name()); ++ ++ bool registered = false; ++ _parent_services.for_each([&] (Parent_service const &service) { ++ if (service.name() == name) ++ registered = true; }); ++ ++ if (!registered) { ++ new (_heap) ::Sandbox::Parent_service(_parent_services, _env, name); ++ if (_verbose->enabled()) { ++ if (first_log) ++ log("parent provides"); ++ log(" service \"", name, "\""); ++ first_log = false; ++ } + } +- } +- }); ++ }); ++ } else { ++ Xml_node const node = config.has_sub_node("parent-provides") ++ ? config.sub_node("parent-provides") ++ : Xml_node(""); ++ ++ /* remove services that are no longer present in config */ ++ _parent_services.for_each([&] (Parent_service &service) { ++ ++ Service::Name const name = service.name(); ++ ++ bool obsolete = true; ++ node.for_each_sub_node("service", [&] (Xml_node service) { ++ if (name == service.attribute_value("name", Service::Name())) { ++ obsolete = false; }}); ++ ++ if (obsolete) ++ service.abandon(); ++ }); ++ ++ /* used to prepend the list of new parent services with title */ ++ bool first_log = true; ++ ++ /* register new services */ ++ node.for_each_sub_node("service", [&] (Xml_node service) { ++ ++ Service::Name const name = service.attribute_value("name", Service::Name()); ++ ++ bool registered = false; ++ _parent_services.for_each([&] (Parent_service const &service) { ++ if (service.name() == name) ++ registered = true; }); ++ ++ if (!registered) { ++ new (_heap) ::Sandbox::Parent_service(_parent_services, _env, name); ++ if (_verbose->enabled()) { ++ if (first_log) ++ log("parent provides"); ++ log(" service \"", name, "\""); ++ first_log = false; ++ } ++ } ++ }); ++ } + } + + +-- +2.28.0 + + +From ee58d1c76d76fa773f4a4c9c446c714429af241e Mon Sep 17 00:00:00 2001 +From: Emery Hemingway +Date: Wed, 4 Nov 2020 20:02:03 +0100 +Subject: [PATCH 3/3] init/sandbox: simplify routing +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Remove , , and configuration +options. + +Allow label rewriting with +and . + +Routes are now selected by longest match rather than first match. +--- + repos/os/src/lib/sandbox/child.cc | 131 ++++++++++------------------ + repos/os/src/lib/sandbox/child.h | 3 - + repos/os/src/lib/sandbox/library.cc | 12 +-- + repos/os/src/lib/sandbox/utils.h | 57 ++++++------ + 4 files changed, 76 insertions(+), 127 deletions(-) + +diff --git a/repos/os/src/lib/sandbox/child.cc b/repos/os/src/lib/sandbox/child.cc +index d25e3d9683..46aa22411c 100644 +--- a/repos/os/src/lib/sandbox/child.cc ++++ b/repos/os/src/lib/sandbox/child.cc +@@ -11,6 +11,7 @@ + * under the terms of the GNU Affero General Public License version 3. + */ + ++#include + #include + + /* local includes */ +@@ -486,105 +487,65 @@ Sandbox::Child::resolve_session_request(Service::Name const &service_name, + return Route { _session_requester.service(), + Session::Label(), Session::Diag{false} }; + +- try { +- /* Lookup route in … */ +- Xml_node route_node = _default_route_accessor.default_route(); +- /* …unless is present… */ +- route_node = _routes_accessor.routes(route_node); +- try { +- /* …otherwise use . */ +- route_node = _start_node->xml().sub_node("route"); } +- catch (...) { } +- +- Xml_node service_node = route_node.sub_node(); +- +- /* is processed with the "«child» -> " prefix */ +- bool skip_prefix = route_node.type() != "routes"; +- +- for (; ; service_node = service_node.next()) { +- +- bool service_wildcard = service_node.has_type("any-service"); +- +- if (!service_node_matches(service_node, label, name(), service_name, skip_prefix)) +- continue; +- +- Xml_node target = service_node.sub_node(); +- for (; ; target = target.next()) { +- +- /* +- * Determine session label to be provided to the server +- * +- * By default, the client's identity (accompanied with the a +- * client-provided label) is presented as session label to the +- * server. However, the target node can explicitly override the +- * client's identity by a custom label via the 'label' +- * attribute. +- */ +- typedef String Label; +- Label const target_label = +- target.attribute_value("label", Label(label.string())); +- +- Session::Diag const +- target_diag { target.attribute_value("diag", false) }; +- +- auto no_filter = [] (Service &) -> bool { return false; }; +- +- if (target.has_type("parent")) { +- +- try { +- return Route { find_service(_parent_services, service_name, no_filter), +- target_label, target_diag }; +- } catch (Service_denied) { } ++ { ++ Xml_node service_node(""); ++ Xml_node routes_node = _routes_accessor.routes(service_node); ++ Xml_node_label_score best_score; ++ ++ routes_node.for_each_sub_node([&] (Xml_node const &node) { ++ if (service_node_matches(node, label, service_name)) { ++ Xml_node_label_score score(node, label); ++ if (score.stronger(best_score) ++ || service_node.has_type("deny")) { ++ best_score = score; ++ service_node = node; + } ++ } ++ }); + +- if (target.has_type("local")) { ++ if (service_node.has_type("deny")) { ++ warning(name(), ": no route to service \"", service_name, "\" (label=\"", label, "\")"); ++ throw Service_denied(); ++ } + +- try { +- return Route { find_service(_local_services, service_name, no_filter), +- target_label, target_diag }; +- } catch (Service_denied) { } +- } ++ for (Xml_node target_node = service_node.sub_node(); ; ++ target_node = target_node.next()) { + +- if (target.has_type("child")) { ++ Session_label the_label_part_of_label(skip_label_prefix(name().string(), label.string())); ++ if (the_label_part_of_label == "") the_label_part_of_label = label; + +- typedef Name_registry::Name Name; +- Name server_name = target.attribute_value("name", Name()); +- server_name = _name_registry.deref_alias(server_name); ++ auto target_label = Sandbox::target_label( ++ target_node, name(), the_label_part_of_label); + +- auto filter_server_name = [&] (Routed_service &s) -> bool { +- return s.child_name() != server_name; }; ++ Session::Diag const ++ target_diag { target_node.attribute_value("diag", false) }; + +- try { +- return Route { find_service(_child_services, service_name, filter_server_name), +- target_label, target_diag }; ++ auto no_filter = [] (Service &) -> bool { return false; }; + +- } catch (Service_denied) { } +- } ++ if (target_node.has_type("parent")) ++ return Route { find_service(_parent_services, service_name, no_filter), ++ target_label, target_diag }; + +- if (target.has_type("any-child")) { ++ if (target_node.has_type("local")) ++ return Route { find_service(_local_services, service_name, no_filter), ++ target_label, target_diag }; + +- if (is_ambiguous(_child_services, service_name)) { +- error(name(), ": ambiguous routes to " +- "service \"", service_name, "\""); +- throw Service_denied(); +- } +- try { +- return Route { find_service(_child_services, service_name, no_filter), +- target_label, target_diag }; ++ if (target_node.has_type("child")) { + +- } catch (Service_denied) { } +- } ++ typedef Name_registry::Name Name; ++ Name server_name = target_node.attribute_value("name", Name()); ++ server_name = _name_registry.deref_alias(server_name); + +- if (!service_wildcard) { +- warning(name(), ": lookup for service \"", service_name, "\" failed"); +- throw Service_denied(); +- } ++ auto filter_server_name = [&] (Routed_service &s) -> bool { ++ return s.child_name() != server_name; }; + +- if (target.last()) +- break; ++ return Route { find_service(_child_services, service_name, filter_server_name), ++ target_label, target_diag }; + } ++ ++ if (target_node.last()) break; + } +- } catch (Xml_node::Nonexistent_sub_node) { } ++ } + + warning(name(), ": no route to service \"", service_name, "\" (label=\"", label, "\")"); + throw Service_denied(); +@@ -712,7 +673,6 @@ Sandbox::Child::Child(Env &env, + Id id, + Report_update_trigger &report_update_trigger, + Xml_node start_node, +- Default_route_accessor &default_route_accessor, + Routes_accessor &routes_accessor, + Default_caps_accessor &default_caps_accessor, + Name_registry &name_registry, +@@ -730,7 +690,6 @@ Sandbox::Child::Child(Env &env, + _report_update_trigger(report_update_trigger), + _list_element(this), + _start_node(_alloc, start_node), +- _default_route_accessor(default_route_accessor), + _routes_accessor(routes_accessor), + _default_caps_accessor(default_caps_accessor), + _ram_limit_accessor(ram_limit_accessor), +diff --git a/repos/os/src/lib/sandbox/child.h b/repos/os/src/lib/sandbox/child.h +index 81836a2045..f9d04cfdaf 100644 +--- a/repos/os/src/lib/sandbox/child.h ++++ b/repos/os/src/lib/sandbox/child.h +@@ -49,7 +49,6 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup + */ + struct Id { unsigned value; }; + +- struct Default_route_accessor : Interface { virtual Xml_node default_route() = 0; }; + struct Default_caps_accessor : Interface { virtual Cap_quota default_caps() = 0; }; + + struct Routes_accessor : Interface +@@ -105,7 +104,6 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup + */ + bool const _use_ld = _start_node->xml().attribute_value("ld", true); + +- Default_route_accessor &_default_route_accessor; + Routes_accessor &_routes_accessor; + Default_caps_accessor &_default_caps_accessor; + Ram_limit_accessor &_ram_limit_accessor; +@@ -481,7 +479,6 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup + Id id, + Report_update_trigger &report_update_trigger, + Xml_node start_node, +- Default_route_accessor &default_route_accessor, + Routes_accessor &route_accessor, + Default_caps_accessor &default_caps_accessor, + Name_registry &name_registry, +diff --git a/repos/os/src/lib/sandbox/library.cc b/repos/os/src/lib/sandbox/library.cc +index caa9840ea6..7b4e72c60e 100644 +--- a/repos/os/src/lib/sandbox/library.cc ++++ b/repos/os/src/lib/sandbox/library.cc +@@ -22,7 +22,6 @@ + #include + + struct Genode::Sandbox::Library : ::Sandbox::State_reporter::Producer, +- ::Sandbox::Child::Default_route_accessor, + ::Sandbox::Child::Routes_accessor, + ::Sandbox::Child::Default_caps_accessor, + ::Sandbox::Child::Ram_limit_accessor, +@@ -134,15 +133,6 @@ struct Genode::Sandbox::Library : ::Sandbox::State_reporter::Producer, + _children.report_state(xml, detail); + } + +- /** +- * Default_route_accessor interface +- */ +- Xml_node default_route() override +- { +- return _default_route.constructed() ? _default_route->xml() +- : Xml_node(""); +- } +- + /** + * Routes_accessor interface + */ +@@ -462,7 +452,7 @@ void Genode::Sandbox::Library::apply_config(Xml_node const &config) + Child &child = *new (_heap) + Child(_env, _heap, *_verbose, + Child::Id { ++_child_cnt }, _state_reporter, +- start_node, *this, *this, *this, _children, ++ start_node, *this, *this, _children, + Ram_quota { avail_ram.value - used_ram.value }, + Cap_quota { avail_caps.value - used_caps.value }, + *this, *this, prio_levels, affinity_space, +diff --git a/repos/os/src/lib/sandbox/utils.h b/repos/os/src/lib/sandbox/utils.h +index 36aab737f2..5cc766a884 100644 +--- a/repos/os/src/lib/sandbox/utils.h ++++ b/repos/os/src/lib/sandbox/utils.h +@@ -58,12 +58,9 @@ namespace Sandbox { + */ + inline bool service_node_matches(Xml_node const service_node, + Session_label const &label, +- Child_policy::Name const &child_name, +- Service::Name const &service_name, +- bool skip_child_prefix = true) ++ Service::Name const &service_name) + { + bool const service_matches = +- service_node.has_type("any-service") || + (service_node.has_type("service") && + service_node.attribute_value("name", Service::Name()) == service_name); + +@@ -72,7 +69,6 @@ namespace Sandbox { + + typedef String Label; + +- char const *unscoped_attr = "unscoped_label"; + char const *label_last_attr = "label_last"; + + bool const route_depends_on_child_provided_label = +@@ -81,34 +77,13 @@ namespace Sandbox { + service_node.has_attribute("label_suffix") || + service_node.has_attribute(label_last_attr); + +- if (service_node.has_attribute(unscoped_attr)) { +- +- /* +- * If an 'unscoped_label' attribute is provided, don't consider any +- * scoped label attribute. +- */ +- if (route_depends_on_child_provided_label) +- warning("service node contains both scoped and unscoped label attributes"); +- +- return label == service_node.attribute_value(unscoped_attr, Label()); +- } +- + if (service_node.has_attribute(label_last_attr)) + return service_node.attribute_value(label_last_attr, Label()) == label.last_element(); + + if (!route_depends_on_child_provided_label) + return true; + +- char const * const scoped_label = skip_child_prefix +- ? skip_label_prefix(child_name.string(), label.string()) +- : label.string(); +- +- if (!scoped_label) +- return false; +- +- Session_label const session_label(scoped_label); +- +- return !Xml_node_label_score(service_node, session_label).conflict(); ++ return !Xml_node_label_score(service_node, label).conflict(); + } + + +@@ -131,6 +106,34 @@ namespace Sandbox { + return cnt > 1; + } + ++ ++ /* ++ * Determine session label to be provided to the server ++ * ++ * By default, the client's identity (accompanied with the a ++ * client-provided label) is presented as session label to the ++ * server. However, the target node can explicitly override the ++ * client's identity by a custom label via the 'label' attribute or ++ * by specifying a 'prefix' and 'suffix attributes. ++ */ ++ typedef String Label; ++ inline Label target_label(Xml_node const node, ++ Child_policy::Name const &child_name, ++ Session_label const &label) ++ { ++ if (node.has_attribute("label")) ++ return Session_label(node.attribute_value("label", Label()).string()); ++ ++ Label head = node.attribute_value("prefix", Label(child_name.string())); ++ Label tail = node.attribute_value("suffix", Label(label.string())); ++ ++ if (head == "") return tail; ++ if (tail == "") return head; ++ ++ return Label(prefixed_label(head, tail).string()); ++ } ++ ++ + /** + * Find service with certain values in given registry + * +-- +2.28.0 + diff --git a/tests/hello.nix b/tests/hello.nix index 5293880..138fed4 100644 --- a/tests/hello.nix +++ b/tests/hello.nix @@ -18,7 +18,8 @@ in { genode.init.children.hello = { configFile = ./hello.dhall; - inputs = [ hello ]; + inputs = [ hello pkgs.genodePackages.vfs.lib ]; + # TODO: libc.lib.so has only relative linking to vfs.lib.so }; }; testScript = '' diff --git a/tests/solo5/net_2if.dhall b/tests/solo5/net_2if.dhall index ff5f713..a9e63d6 100644 --- a/tests/solo5/net_2if.dhall +++ b/tests/solo5/net_2if.dhall @@ -33,13 +33,13 @@ let init = , service = "Nic" , attributes = toMap { ip_addr = "10.0.0.2" } , label = - Init.LabelSelector.Type.Scoped "solo5 -> service0" + Init.LabelSelector.Type.Full "solo5 -> service0" } , Init.Config.Policy::{ , service = "Nic" , attributes = toMap { ip_addr = "10.1.0.2" } , label = - Init.LabelSelector.Type.Scoped "solo5 -> service1" + Init.LabelSelector.Type.Full "solo5 -> service1" } ] }