Skip to content

nvx-rs slimming 2.1.2: the kernel command line and OpenVMM's arguments come from the configuration alone #1098

Closed

Description

Parent: #1079, in #1076. Needs: #1091, #1097. Unblocks: #1099, #1104, #1124.

Goal. A cold boot's kernel command line and OpenVMM's arguments come from Runtime and VmConfig alone. The root's tokens carry the overlay mode, the journal policy, the GPT bound and the RAM upper's cap; the caller's command line can't override the tokens that nvx renders (the root's, the view's and nvx_maps), and owns every other token; and a caller can see the mapping table and the native egress rules that its policy lowers to. The new renderer never passes --microvm-lifecycle or --microvm-workload-identity. A caller can check, before anything changes on the host, that a configuration's command line fits Windows' limit, and the helpers that count and check a Windows command line stay public.

Notes.

PRs, in order. Each PR has one goal, leaves dev green, and names in its description each old test of its area as kept, rewritten or retired, with each change that check_test_changes.py reports. Its tests follow the repository's test layout: a module's unit tests, and the code that only they use, sit in its tests.rs or tests/ and move with it. The estimates count core lines (code, not comments, docs or tests) and counted files; each PR records its measured values. Each PR does what its Scope says and no more: a case, input or layout that its Scope doesn't name, and whatever "Not in this PR" lists, is out of scope. Address every review comment within the scope, and ask before acting on one that asks for more. A PR whose measured core lines pass the stop that its Estimate names (twice the estimate, at most 600) stops and asks before continuing.

  1. SL2.4a1: The root's kernel tokens carry what VmConfig sets, and the guest caps a RAM upper.

    • Objective: The layered-root boot tokens omit configuration that the guest needs to reproduce the requested root. The tokens and parser carry the overlay mode, journal policy, GPT bound and RAM-upper cap, and the guest applies the cap when mounting tmpfs.
    • Contents: The root's tokens gain the overlay mode, the journal policy, the GPT bound and the RAM upper's cap, with their parser; root::assemble mounts a RAM upper with size=N%.
    • Scope:
      • Extend nvx-rs/src/protocol/root.rs tokens and parsing for both existing image formats, both existing upper kinds, both overlay modes, the journal policy, optional GPT first-partition bound and RAM cap.
      • Update the shared recorded command-line fixtures so every root-token reader sees the new fields alike.
      • Update nvx-rs/src/guest/root.rs assembly so a RAM upper mounts tmpfs with size=N%.
      • Keep BOOT_CONTRACT_VERSION unchanged because no released build uses these new tokens.
    • Not in this PR:
      • A new image format, upper kind, overlay mode or journal policy: the tokens cover only the variants already represented by VmConfig.
      • Rendering the complete kernel command line from VmConfig: SL2.4a2 composes the root, view, mapping and caller tokens.
      • Changing the activation record or restore-time root repair: SL2.5b carries the RAM cap in the record.
      • Fallback probing when tokens are absent or malformed: the existing parser remains strict.
      • Incrementing the boot contract version: the group issue explicitly keeps it unchanged.
    • Approach: Extend the existing protocol::root codec and fixture rather than adding a second root protocol. Pass the parsed RAM percentage to the current tmpfs mount as size=N%; retain the existing EROFS, GPT, scratch and RAM assembly paths.
    • Done when:
      • wire_values_keep_their_literals names the added token literals while the boot contract version remains unchanged.
      • every_layout_renders_its_tokens_and_reads_them_back and the recorded-command-line test cover every existing format, upper and overlay combination with the new fields.
      • both_overlay_modes_assemble_on_both_uppers_with_their_own_option_sets observes size=N% for RAM uppers.
      • a_tmpfs_upper_needs_no_scratch_device still passes with the capped tmpfs mount.
    • Needs: SL2.3a, in nvx-rs slimming 2.1.1: one value for a VM's configuration #1097.
    • Estimate: 120 core lines, 3 counted files. Past 240 core lines, stop and ask before continuing.
  2. SL2.4a2: A cold boot's kernel command line comes from VmConfig alone.

    • Objective: Cold-boot command lines are assembled by launch-specific code instead of the VM configuration. VmConfig::kernel_command_line becomes the single pure renderer for the root, view, mapping count and caller-owned tokens.
    • Contents: protocol::view: the view's tokens and their parser. VmConfig::kernel_command_line: the root's tokens, the view's and nvx_maps, then Boot.command_line. Parity tests compare it with the old rendering, through test-only conversions.
    • Scope:
      • Add nvx-rs/src/protocol/view.rs for nvx_hostname and nvx_machine_id, with rendering and strict parsing.
      • Add VmConfig::kernel_command_line, ordered as the root tokens, view tokens, nvx_maps when an export exists, then Boot.command_line.
      • Add the parity conversions in an impl block in host/config/tests.rs; add the new view codec's parser cases in protocol/view/tests.rs.
      • Render only cold boots, which have Boot; restores receive their view through the activation record.
    • Not in this PR:
      • Rejecting caller tokens that conflict with rendered tokens or virtfs_*: SL2.4b adds those checks.
      • Rendering NVX's own guest tokens such as nvx_entrypoint, nvx_arg or nvx_share: callers keep those in Boot.command_line.
      • Rendering OpenVMM process arguments: SL2.4c consumes this kernel command line.
      • A generic kernel-command-line builder or quoting grammar: the kernel tokens use the existing protocol::cmdline rules.
      • Changing restore activation records or removing WorkloadView: SL2.5b handles the record.
    • Approach: Reuse the root codec, export mapping count and protocol::cmdline parsing conventions. Add one narrow view codec and concatenate the four specified token groups in order; keep compatibility conversions inside the owning module's tests module, not in a production file, instead of retaining a second production renderer.
    • Done when:
      • The protocol::view parser round-trips valid hostname and machine-ID tokens and refuses each malformed or duplicate token case.
      • Parity tests match today's root tokens, view values and nvx_maps count through test-only conversions.
      • A caller's command line appears after all rendered tokens without being otherwise rewritten.
    • Needs: SL2.4a1, above; SL2.3b, in nvx-rs slimming 2.1.1: one value for a VM's configuration #1097.
    • Estimate: 130 core lines, 3 counted files. Past 260 core lines, stop and ask before continuing.
  3. SL2.4b: The caller's command line can't override the tokens that nvx renders.

    • Objective: Caller-supplied boot tokens must not replace the root, view or mapping configuration that VmConfig renders. The configuration rejects only those collisions, exposes the exact mapping table behind nvx_maps and makes the existing map codec directly accessible.
    • Contents: The refusal of the tokens that nvx renders (the root's, the view's and nvx_maps) and of virtfs_* in Boot.command_line; the caller owns every other token; VmConfig::mapping_table; COMMAND_LINE_BUDGET moves from host::launch to host::config. protocol::maps becomes a public module, and protocol's root keeps its re-exports.
    • Scope:
      • Reject the root tokens, nvx_hostname, nvx_machine_id, nvx_maps and every virtfs_* token in Boot.command_line.
      • Accept all other caller tokens, including nvx_entrypoint, nvx_arg and nvx_share.
      • Add VmConfig::mapping_table() from the configured export, with exactly the entries counted by the rendered nvx_maps token.
      • Move COMMAND_LINE_BUDGET from nvx-rs/src/host/launch.rs to host::config.
      • Make protocol::maps public while retaining the existing re-exports from protocol.
    • Not in this PR:
      • Rejecting every token whose name starts with nvx_: callers own the tokens that VmConfig does not render.
      • Changing the mapping-table wire format, limits or codecs: this PR only exposes the existing module and returns its existing entries.
      • Reading mappings from the host or validating mapped paths again: mapping_table() is a pure projection of the checked export plan.
      • Rendering OpenVMM arguments or checking the Windows process limit: SL2.4c does both.
      • Moving other launch constants or deleting the old launch checks: later migration PRs remove the legacy configuration.
    • Approach: Parse Boot.command_line with the existing kernel-token reader, normalize names as the kernel does, reject the fixed root, view and mapping names, and reject any normalized name beginning virtfs_. Reuse ExportPlan::guest_table() for mapping_table() and expose the existing maps module; do not add a blanket namespace policy or a second mapping representation.
    • Done when:
      • The rewritten kernel-parameter tests refuse every root, view, mapping and virtfs_* spelling that the kernel treats as the same name.
      • Tests accept representative caller-owned guest tokens rather than reserving the full nvx_* namespace.
      • mapping_table() returns exactly the entries counted by nvx_maps when an export exists; without an export, the table is empty and nvx_maps is absent.
      • Existing users of the root-level map re-exports still compile after protocol::maps becomes public.
    • Needs: SL2.4a2, above.
    • Estimate: 150 core lines, 2 counted files. Past 300 core lines, stop and ask before continuing.
  4. SL2.4c: A cold boot's OpenVMM arguments come from Runtime and VmConfig alone.

    • Objective: Cold-boot OpenVMM arguments are spread across legacy launch and plan paths, so callers cannot inspect one configuration-derived result before host changes begin. A temporary whole-configuration renderer and a portable length check derive the arguments from Runtime and VmConfig alone.
    • Contents: Processors, memory, block devices by path, blockless and layered roots, the network's and the export's arguments (internal), the console's attachment, and LaunchOptions. It never renders --microvm-lifecycle or --microvm-workload-identity. Until SL2.8 calls it, the whole-config renderer is a temporary public entry point, documented as such; SL2.8 makes it internal. The Windows command-line limit stays: PROCESS_COMMAND_LINE_LIMIT, process_command_line_units and fit_process_command_line stay public, in host::config, and VmConfig::check_command_line() (new) renders the configuration's arguments and checks, on every host and before anything changes on it, that they fit with a reserve for the runtime's files and the VM directory's paths, as check_adapter_launch does for the old plan.
    • Scope:
      • Render processors, memory, kernel command line, block devices by path, blockless and layered roots, network and export arguments, console attachment and every LaunchOptions value.
      • Never emit --microvm-lifecycle or --microvm-workload-identity.
      • Expose the whole-config renderer temporarily and document that SL2.8 makes it internal when host::vm::create calls it.
      • Move PROCESS_COMMAND_LINE_LIMIT, process_command_line_units and fit_process_command_line from host::launch to host::config without narrowing their public use.
      • Add VmConfig::check_command_line() to render and check on every host with reserve for the runtime files and VM-directory paths before host state changes.
    • Not in this PR:
      • Opening block devices, resolving final paths, passing file descriptors or guarding the check-to-open interval: this interface passes repository block devices by path.
      • Starting OpenVMM, creating a VM directory or allocating endpoints and reports: SL2.8's create prepares a launch and makes the renderer internal, and SL2.9's spawn starts OpenVMM.
      • Public renderers for the network, export or individual device parts: only the whole-configuration renderer is public temporarily.
      • Restore arguments or snapshot compatibility: this renderer covers cold boots from Runtime and VmConfig.
      • Changing policy normalization or exposing native egress rules: SL2.4d is separate.
    • Approach: Refactor the existing LaunchSpec, VmmLaunch, network and export argument assembly into one renderer over the new values. Reuse the current Windows quoting counter and reserve model, and keep part lowerings internal; do not build a command object hierarchy, path-handle layer or host-specific preflight.
    • Done when:
      • Renderer tests cover processors, memory, block devices by path, blockless and layered roots, network, export, both console attachments and every launch-option value.
      • No renderer case contains --microvm-lifecycle or --microvm-workload-identity.
      • VmConfig::check_command_line() accepts a fitting configuration with the reserve and rejects one beyond it with the same result on every host.
      • The public counting helpers retain their Windows quoting cases, including spaces, quotes, backslashes, empty arguments and non-ASCII text.
    • Needs: SL2.4b, above.
    • Estimate: 550 core lines, 5 counted files. Past 600 core lines, stop and ask before continuing.
  5. SL2.4d: A caller can see the native egress rules that its policy lowers to.

    • Objective: Callers can construct a NetworkPolicy but cannot inspect the canonical native allow and deny rules it produces without going through the policy-file compiler. A pure query exposes that existing normalization directly and reports an oversized result as an Unsupported error.
    • Contents: NetworkPolicy::native_egress_rules() -> Result<NativeEgressRules> (new), where NativeEgressRules { allow, deny } holds the native rules (CIDR, CIDR:PROTOCOL, CIDR:PROTOCOL:PORT or CIDR:PROTOCOL:FIRST-LAST) that the policy's allow and deny rules lower to, from the internal normalization: destinations merged, exceptions subtracted and port ranges merged. Each list holds at most MAX_RULES; more is an Unsupported error. It is pure: it reads no policy file and nothing else on the host. The compiler's MAX_RULES_PER_ACTION already aliases network::MAX_RULES; lowering takes the limit from network instead of policy, so the normalization no longer depends on the compiler.
    • Scope:
      • Add NetworkPolicy::native_egress_rules() -> Result<NativeEgressRules> in host::network.
      • Add NativeEgressRules { allow, deny }, containing the existing canonical CIDR, protocol, port and port-range strings for IPv4 and IPv6 rules.
      • Reuse the internal normalization that merges destinations, subtracts exceptions, merges port ranges and sorts each action.
      • Limit each list to MAX_RULES; return an Unsupported error when normalization needs more.
      • Make host::network::lowering take its limit from network::MAX_RULES rather than the policy-file module.
    • Not in this PR:
      • Reading JSON or any policy file: the method operates only on the already constructed NetworkPolicy.
      • A new rule grammar or normalization algorithm: outputs stay identical to the existing policy compiler's canonical rules.
      • Changing OpenVMM network arguments, ingress, host-loopback, forwards or proxy behavior: the query exposes egress allow and deny lowering only.
      • Making address parsing or lowering public: callers receive only the two native string lists.
      • Host I/O, network probes or rule installation: the method is pure.
    • Approach: Route the public EgressRule values through the current internal parsing and lowering functions, then wrap the two resulting vectors. Move the shared limit dependency downward to host::network; do not duplicate the compiler, expose its internals or retain a dependency on the policy-file reader.
    • Done when:
      • Existing subtraction and adjacent-or-overlapping range tests pass through native_egress_rules() with the same canonical strings.
      • Exactly 256 native rules per allow or deny list are accepted, while 257 are rejected before materializing an oversized result.
      • Tests cover destination merging, exception subtraction and port-range merging without reading a file or other host state.
    • Needs: SL0.4, in nvx-rs slimming 1.1.1: the public API is checked, and NVX's programs are hidden from it #1091.
    • Estimate: 80 core lines, 3 counted files. Past 160 core lines, stop and ask before continuing.

Tests. SL2.4a1 rewrites protocol::root's wire_values_keep_their_literals, every_layout_renders_its_tokens_and_reads_them_back and every_reader_parses_the_recorded_command_lines_alike for the overlay mode, the journal policy, the GPT bound and the RAM cap, and the_boot_contract_version_names_these_tokens for the new tokens, with BOOT_CONTRACT_VERSION unchanged, and guest::root's both_overlay_modes_assemble_on_both_uppers_with_their_own_option_sets and a_tmpfs_upper_needs_no_scratch_device to show that the tmpfs upper mounts with size=N%. SL2.4a2's parity tests compare the new kernel command line with the old renderers, through test-only conversions: the root's and the view's tokens, and nvx_maps; protocol::view's parser round-trips nvx_hostname and nvx_machine_id, and refuses each malformed token. SL2.4b rewrites host::launch's mappings_add_the_export_and_the_mapping_count, kernel_parameters_are_checked and kernel_parameters_are_read_as_the_kernel_reads_them: the rendered tokens and virtfs_* are refused, a caller's own guest tokens are accepted, and mapping_table() has exactly the entries that nvx_maps counts. SL2.4c rewrites arguments_select_the_managed_direct_guest, and covers processors, memory, block devices by path, blockless and layered roots, the network, the export, both console attachments and each LaunchOptions value; no case renders --microvm-lifecycle or --microvm-workload-identity. SL2.4d keeps the policy normalization's tests, such as test_subtracts_rule_local_cidr_exclusions, test_merges_adjacent_and_overlapping_ranges_of_one_network, test_accepts_exact_256_rule_boundaries and test_rejects_257_rules_before_materializing_them, through native_egress_rules(), with no host I/O. SL2.4c's tests cover VmConfig::check_command_line: a configuration that fits with the reserve, one that doesn't, the same answer on every host, and the counting helpers' quoting.

Done when: every PR above has merged, with dev green.

Activity

  1. esaurez commented on Nov 10, 2026

    @esaurez
    ContributorAuthor

    Workstream source/progress checkpoint - 2026-11-10 UTC

    Checked boxes below mean merged scope, not merely an implemented first iteration. Implementation branches are source checkpoints, not automatic qualification, Ready or merge approval. Some starting inputs are frozen/anonymous commits rather than standalone branches; their exact SHAs and known merged producer refs are recorded explicitly.

    The original technical scope remains authoritative, supplemented only by any portable technical clarification in this issue. No machine-specific execution policy is part of this checkpoint.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions