Skip to content

nvx-rs: give each network policy a template of its own, and start network clones - #958

Merged
Pedro Henrique Penna (ppenna) merged 2 commits into
devfrom
esaurez/846-pr2-network-templates-20261025
Oct 29, 2026
Merged

Pedro Henrique Penna (ppenna) merged 2 commits into
devfrom
esaurez/846-pr2-network-templates-20261025

Conversation

@esaurez

@esaurez Enrique Saurez (esaurez) commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Chain: #951 → #954 → #957 → #959 → #960 → #955 → this PR, on dev; #879, #881, #885, #886, #877, #932, #884, #887, #933, #880, #936, #937, #939, #940, #941, #888, #949, and #950 have merged.

Stacked on #955. Part of #846 (PR 2 of 2: network templates). It builds on PR 1 (#955), and on the network settings that #845's PR 3 (#960) gives a clone.

One template per network policy

A template's NIC is restored with the network that its capture attached, so a template can serve only the clones of that network. Before this change, a clone's plan checked only that the template had a NIC when the clone's plan had a network, at the guest address and prefix of that NIC, and the restore passed the policy of the clone's own network. OpenVMM then refused another policy at the restore, after the VMM started.

The template key now holds the network as the capture class lowered it to OpenVMM's arguments, SandboxNetwork::openvmm_arguments: --net with the guest's address and prefix, then the options of the policy. A template without a NIC holds none, and so does a network that lets nothing through, which attaches no NIC either: they share the no-network identity. NVX already has that lowering, so the key holds no new digest, and nothing is hashed.

  • ClonePlan::new lowers the network of the adapter's plan and compares it with the key's. It refuses, before any VMM starts, a network for a template without a NIC, none for a template with one, and another policy or guest address. Each is a failure of the request, Evidence::InvalidSettings. This one comparison replaces the check of the guest's address that nvx-rs: attribute a clone's failures, record them, and reattach it #951 made, and keeps that check's message for another address or prefix.
  • ClonePlan::launch passes the key's network unchanged, but --net and the address, which OpenVMM takes from the snapshot and refuses beside it. The clone's own plan no longer adds a network to the restore, so the restore has no --net of the plan's to drop.
  • No clone gets ingress, host-loopback access to its listeners, or forwards: a template's capture refuses a policy that allows ingress or two-way host-loopback access, which forwards need. Listener publication stays with nvx-rs: per-clone network policies on deny-all templates #850.

The key's network

The key's canonical encoding takes the network as its eighth part, a list of texts, and stays version 1. TemplateKey::from_bytes checks that the list is exactly the arguments to which a network of a guest at the NIC's address lowers: it reads the policy back from them, as nvx-rs sandbox reads its network options, and lowers it again with the NIC attached, network::attached_arguments, since a closed policy whose allow rules lower to no OpenVMM rule still attaches its NIC. For a machine without a NIC, the list is empty. A key whose network no policy lowers to is malformed, which ClonePlan::new attributes to the generation, rather than accepted with a network that every clone's plan mismatches. The check is CPU work alone, with no I/O or hashing.

  • The key's encoding has not been released, so a template store that an earlier build created is not supported: delete it and create a new one. There is no migration, and no compatibility code: the key's version, the capture class, and the template store's record format, STORE_FORMAT, stay as they were. Every key ends with its network, an empty list for a template without a NIC, so bytes without it are refused as malformed, the generation's failure, Evidence::MalformedGeneration, and never read as the key of a template without a NIC. A key of another version stays the host's, Evidence::IncompatibleHost, which quarantines nothing.
  • The key's vectors in nvx-rs/tests/vectors/template-key-v1.txt change in place, generated from the definition, which nvx-rs/tests/vectors/README.md records as the second exception to its rule that a vector changes only with a version. The capture class's encoding and vectors are unchanged.

Starting a clone of a network template

runtime-adapter-host start takes a launch's --network FILE, which it reads before anything else, as a launch does, and refuses with status 1 if it cannot read it or the plan refuses it. clone::Request carries the network, and Request::plan puts it on the adapter's plan, which NVX's plan compares with the template's.

The clone's record keeps the plan, with its network, so exec gives a clone's executions the URL of the network's proxy in http_proxy, https_proxy, HTTP_PROXY, and HTTPS_PROXY, as for a launch. It is the URL that the clone's activation record names, since both come from the same plan.

Tests

  • Key: the network that a class lowered, round-tripped, for every form of policy (rules of both families, outbound and two-way host-loopback access with forwards, a proxy, and a closed policy whose allow rule excepts its whole destination, with and without deny rules); a closed network, which has the no-network identity; a key that changes with an egress rule or default; and the refusals of a network without a NIC, a NIC without a network, a network at another address, networks that no policy lowers to (the address alone, options out of order, another profile, a rule that OpenVMM would not read or that a lowering writes in another form, an option without its value, an unknown option, the address twice, and a proxy beside allowed egress), a key without its network, and keys of other versions. The vectors cover each refusal. network::attached_arguments renders the closed policy's device as one more allow rule that lowers to no OpenVMM rule does, and any other policy as openvmm_arguments does.
  • Clone planning and launch, with a fake VMM: against a template with a NIC, another guest address and another prefix, refused with the message of nvx-rs: attribute a clone's failures, record them, and reattach it #951's check, and three other policies at the template's address; a network refused against a template without one; and the restore's arguments, which are the key's.
  • Test adapter: start --network refused when given twice; a network that cannot be read, or that the plan refuses, refused before the image, the shares, and the template store; and a request with a proxy-only network, whose plan, NVX request, and record carry the network, so that an execution finds the proxy's URL.
  • VM tests (vm_clone), on KVM, MSHV, and WHP:
    • A template without a NIC serves clones without a network and of a network that lets nothing through: no network device, no network in the record, and the image's own /etc/resolv.conf, which no bind holds. A clone of each network with a NIC is refused before any VMM starts.
    • A template of each network with a NIC that a capture takes (egress allowed, with or without outbound host-loopback access, an allow rule, and a proxy) serves a clone of its own network. The clone has one network device, on Linux the VMM's arguments of the template's policy without --net, and a record that names the policy, the gateway's DNS server where egress is allowed, and the proxy. Its restored NIC lets through what the policy allows alone: the tests bind three listeners on host loopback, the proxy's, the allow rule's, and one that no network names, at ports that the host chooses, and an execution's TCP connection to the gateway at each port opens, and arrives at the listener, where the policy lets it through, and fails, with nothing arriving, elsewhere. The allow rule's clone reaches its listener alone, the proxy-only clone the proxy alone, the clone with egress and outbound host-loopback access all three, and the clone with egress allowed alone none. Each other network, the same policy at another guest address, a closed network, and no network are refused before any VMM starts. The templates' policies differ.
    • DNS: with egress allowed, /etc/resolv.conf is a file of mode 0444 that names the gateway's DNS server, held by a read-only, nosuid, nodev bind after that of a generated machine ID, which mount tables list. A write as root cannot change it. A TCP connection to the server's DNS port opens, which the gateway's DNS proxy accepts itself, so the check does not depend on the host's resolver or its upstream servers.
    • Status 57: a clone of a disk whose layer holds a regular file etc ends before it is ready, by the evidence of invalid settings.
    • Proxy: the executions of a clone of a proxy-only network find the proxy's URL after their own entries, and one that names its own proxy settings keeps them.
    • A clone of a template with a NIC maps its export below the binds of its machine ID and its resolver configuration.

The scenarios of exports from PR 1 keep templates without a NIC, so their mount tables hold no resolver configuration.

Validation

At this PR's head e19ceed, the commits of the earlier head e9e7fc6 are rebased unchanged onto #955's head 551ebda. Its tree, 21eab61f, is the merge of e9e7fc6 into dev at fbeb563, which holds #951, #954 and #957, on top of #960's head efe51b4. It adds #955's fix from a review thread, which makes ExportPlan::verify report a path whose links loop as a changed object. CI at this head, in run 40901423035: 36 jobs passed, among them the microVM tests and the platform checks on KVM, MSHV and WHP, and OpenVMM's unit and VM tests; the six that run only for a pull request or on dev were skipped. CI at the head before #955's fix, 2a777a3, whose tree, acbf8180, is that merge alone, in run 40896659416, passed the same way. A pre-check of acbf8180 passed on Linux and on Windows: the library's documentation with -D warnings; the test adapter's documentation in its protocol-only and host configurations, and in its musl guest configuration on Linux; validate-nvx; and the Markdown links. At this head, for #955's fix, on Windows: fmt; Clippy with -D warnings of all targets with all features, and of all targets with all features for x86_64-unknown-linux-musl; and the tests of host::filesystem and tests/host_modules.rs. On Linux x86_64: Clippy of all targets with all features, the tests of host::filesystem, and the aarch64-apple-darwin check. The rest of this section describes the validation at e9e7fc6, on #955's earlier head 08d111c.

At the final restack, onto #955's head with OpenVMM 832d5bb4, each commit on its own:

  • Windows: nvx-rs's fmt; Clippy with -D warnings of all targets with all features, of the library with the default features and without them, and of all targets with all features for x86_64-unknown-linux-musl; tests/host_modules.rs; and the library tests of host::template, host::filesystem, host::network, and protocol. The test adapter's fmt; Clippy of its protocol-only, host, and x86_64-unknown-linux-musl guest configurations; and its protocol-only, host library, host_session, and clone_start tests. The check of the README's module table in scripts/test_nvx_tools.py.
  • Linux: the macOS check; the guest::mappings and guest::managed_agent tests, as the user and as root with the root-only tests; and the test adapter's guest library and guest_session tests for x86_64-unknown-linux-musl.
  • At this head, also: the docs with -D warnings, MSRV 1.89 of nvx-rs and of the test adapter's three configurations, and the Markdown link check.

At this head:

  • The CI workflow: every job passed, the VM tests on KVM, MSHV, and WHP included, where the test adapter's vm_clone passed 25 of 25, the export and network scenarios included, and vm_template 9, vm_layered 43, vm_restart 3, and vm_steps 3.
  • Windows: the nvx-rs checks (fmt; Clippy of all targets with all features, of the library with the default features, and of the library without them; tests with all features, the defaults, and without default features; docs; MSRV 1.89), Clippy of its guest code for x86_64-unknown-linux-musl, tests/host_modules.rs, the test adapter's protocol-only and host checks and Clippy of its guest, the check of the README's module table, scripts/nvx.py verify, and the Markdown link check.
  • Linux: the same nvx-rs checks, its macOS check, and Clippy of its guest code for x86_64-unknown-linux-musl; the lint and the tests of the guest binaries (scripts/nvx.py check-guest-binaries); the test adapter's protocol-only, host, and guest configurations, each with its Clippy, build, tests, and MSRV; and, as root, the tests that need it (198 of 198, the 13 that only root runs included).
  • On MSHV and WHP, with the OpenVMM of the development release v0.1.0-dev.2d14547b669f, which nvx-rs download installed, and the initramfs and the test adapter's guest agent built from the tree: vm_clone 25 of 25, vm_template 9, vm_layered 43, vm_restart 3, and vm_steps 3.

These runs hold for this head, e9e7fc6, by tree identity: the CI workflow ran at cfdc779, and the Windows, Linux, and VM runs at 954d098, before this branch's fix-ups were squashed into its second commit, which changed no file. cfdc779 has this head's tree, 72dea16c, and 954d098's tree differs from it in a comment alone.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Obsolete version-1 keys can block template startup and recovery after upgrades, while malformed network arguments can be accepted instead of quarantined.

3 open issues
What changed in this PR

Implements policy-specific network templates for NVX clones as the second part of #846, building on the export support in #955/#956 and network activation settings from #845.

Changes:

  • Adds network arguments to version-2 template keys, rejects mismatched clone networks before launch, and restores the template’s policy.
  • Adds start --network support to the runtime adapter and preserves proxy settings for clone executions.
  • Expands key, planning, CLI, and VM tests for network compatibility, DNS, proxies, and exports alongside resolver mounts.
File Description
tests/​runtime-adapter/​tests/​vm_clone.rs Adds network-clone VM scenarios.
tests/​runtime-adapter/​tests/​clone_start.rs Tests network options, early rejection, and proxy persistence.
tests/​runtime-adapter/​src/​clone.rs Carries network settings through clone requests and plans.
tests/​runtime-adapter/​src/​bin/​runtime-adapter-host.rs Accepts and reads start --network.
tests/​runtime-adapter/​README.md Documents network clones and their test scenarios.
nvx-rs/​tests/​vectors/​README.md Documents version-2 key vectors.
nvx-rs/​src/​host/​template/​store/​tests.rs Tests rejection of version-1 keys.
nvx-rs/​src/​host/​template/​mod.rs Updates template compatibility documentation.
nvx-rs/​src/​host/​template/​key/​tests.rs Tests network identities, decoding, and version-2 conformance.
nvx-rs/​src/​host/​template/​key.rs Encodes network arguments in version-2 keys.
nvx-rs/​src/​host/​template/​clone/​tests/​launch.rs Checks restore arguments against the template’s network.
nvx-rs/​src/​host/​template/​clone/​tests.rs Tests policy mismatches and obsolete-key failures.
nvx-rs/​src/​host/​template/​clone/​launch.rs Uses the template’s network arguments during restore.
nvx-rs/​src/​host/​template/​clone.rs Enforces network compatibility before launch.
nvx-rs/​README.md Updates library documentation for policy-specific templates.

Review effort: Balanced

Comment thread nvx-rs/src/host/template/key.rs Outdated
Comment thread nvx-rs/src/host/template/key.rs Outdated
Comment thread nvx-rs/src/host/template/key.rs Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The version bump can strand existing templates and block store recovery, while fully excluded network allow rules can produce keys that fail round-trip validation.

3 open issues
1 resolved since last review

Review effort: Balanced

Comment thread nvx-rs/src/host/template/key.rs

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The clone tests do not verify post-restore traffic enforcement for allow-rule and proxy-only policies, leaving policy enforcement regressions undetected.

1 open issue
3 resolved since last review

Review effort: Balanced

Comment thread nvx-rs/src/host/template/clone/launch.rs

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The current OpenVMM pin lacks the required export fix, and the restacked head still needs VM validation across KVM, MSHV, and WHP.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

Enrique Saurez (esaurez) pushed a commit that referenced this pull request Oct 28, 2026
This branch exists only to run CI. It is never a pull request's head,
and this commit never goes onto a pull request's branch.

It is #958's head, 4a614d9, which holds #955, #956, and #958, with
the fixes that dev carries for the failures that their review bases,
pinned to OpenVMM 79a501b6, show in CI, and that the pull requests do
not change:

- #885's test-only 3fbaf8a, cherry-picked before this commit. On
  GitHub's hosted Windows runners an open with backup semantics
  bypasses the test's access list.
- This commit, which moves the openvmm gitlink 79a501b6 -> e68871cc,
  the virtio-fs fix of #904 that dev pins since #918, so that a clone's
  export serves requests after a gated restore. The platform tier's
  allowlist there admits maxcpus=, so the copy of it in
  nvx-rs/tests/vectors/openvmm, which the CLI jobs compare with the
  submodule, takes that line too.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 34e6ffe3-3ebf-42db-bfca-e0ecfade6873
Enrique Saurez (esaurez) pushed a commit that referenced this pull request Oct 28, 2026
This branch exists only to run CI. It is never a pull request's head,
and this commit never goes onto a pull request's branch.

It is #958's head, 4a614d9, which holds #955, #956, and #958, with
the fixes that dev carries for the failures that their review bases,
pinned to OpenVMM 79a501b6, show in CI, and that the pull requests do
not change:

- #885's test-only 3fbaf8a, cherry-picked before this commit. On
  GitHub's hosted Windows runners an open with backup semantics
  bypasses the test's access list.
- This commit, which moves the openvmm gitlink 79a501b6 -> e68871cc,
  the virtio-fs fix of #904 that dev pins since #918, so that a clone's
  export serves requests after a gated restore. The platform tier's
  allowlist there admits maxcpus=, so the copy of it in
  nvx-rs/tests/vectors/openvmm, which the CLI jobs compare with the
  submodule, takes that line too.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 34e6ffe3-3ebf-42db-bfca-e0ecfade6873
Enrique Saurez (esaurez) pushed a commit that referenced this pull request Oct 28, 2026
This branch exists only to run CI. It is never a pull request's head,
and this commit never goes onto a pull request's branch.

It is #958's head, 4a614d9, which holds #955, #956, and #958, with
the fixes that dev carries for the failures that their review bases,
pinned to OpenVMM 79a501b6, show in CI, and that the pull requests do
not change:

- #885's test-only 3fbaf8a, cherry-picked before this commit. On
  GitHub's hosted Windows runners an open with backup semantics
  bypasses the test's access list.
- This commit, which moves the openvmm gitlink 79a501b6 -> e68871cc,
  the virtio-fs fix of #904 that dev pins since #918, so that a clone's
  export serves requests after a gated restore. The platform tier's
  allowlist there admits maxcpus=, so the copy of it in
  nvx-rs/tests/vectors/openvmm, which the CLI jobs compare with the
  submodule, takes that line too.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 34e6ffe3-3ebf-42db-bfca-e0ecfade6873
Enrique Saurez (esaurez) pushed a commit that referenced this pull request Oct 28, 2026
This branch exists only to run CI. It is never a pull request's head,
and this commit never goes onto a pull request's branch.

It is #958's head, 4a614d9, which holds #955, #956, and #958, with
the fixes that dev carries for the failures that their review bases,
pinned to OpenVMM 79a501b6, show in CI, and that the pull requests do
not change:

- #885's test-only 3fbaf8a, cherry-picked before this commit. On
  GitHub's hosted Windows runners an open with backup semantics
  bypasses the test's access list.
- This commit, which moves the openvmm gitlink 79a501b6 -> e68871cc,
  the virtio-fs fix of #904 that dev pins since #918, so that a clone's
  export serves requests after a gated restore. The platform tier's
  allowlist there admits maxcpus=, so the copy of it in
  nvx-rs/tests/vectors/openvmm, which the CLI jobs compare with the
  submodule, takes that line too.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 34e6ffe3-3ebf-42db-bfca-e0ecfade6873
@esaurez
Enrique Saurez (esaurez) force-pushed the esaurez/846-pr2-network-templates-20261025 branch from 584e684 to 200a65e Compare October 29, 2026 06:40
@esaurez
Enrique Saurez (esaurez) changed the base branch from esaurez/846-vm-tests-20261025 to esaurez/846-pr1-export-maps-20261025 October 29, 2026 06:41
@esaurez
Enrique Saurez (esaurez) requested a balanced review from Copilot October 29, 2026 06:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The DNS test depends on the host’s upstream resolver, so a slow or unreachable upstream can cause a timeout and falsely fail the restored-network test.

1 open issue

Review effort: Balanced

Comment thread tests/runtime-adapter/tests/vm_clone.rs Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Human assessment is needed because a no-traffic network can still attach a NIC in an excluded-destination edge case, contrary to the documented behavior.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Backend-dependent network isolation and restore behavior still need exact-head VM and CI validation across KVM, MSHV, and WHP.

No open issues 🎉

Review effort: Balanced

@esaurez
Enrique Saurez (esaurez) force-pushed the esaurez/846-pr2-network-templates-20261025 branch from cfdc779 to e9e7fc6 Compare October 29, 2026 07:43
@esaurez Enrique Saurez (esaurez) removed their assignment Oct 29, 2026
Enrique Saurez (esaurez) pushed a commit that referenced this pull request Oct 29, 2026
…in VMs

The VM scenarios of templates and clones tested the interim rule, under
which each network policy had a template of its own, and templates
refused ingress and host-loopback access both ways.

vm_template now creates one template of a network that publishes the
guest's listeners and forwards a port: its key's command line names the
NIC's addresses, but neither a DNS server nor a publication, and the
creation of each other network at the same guest's address serves it
without a capture.

vm_clone starts the clones of every network policy from one template:
each restore installs the clone's own policy, and the clone's record
names its DNS server, proxy, and publication. Through listeners of the
host on host-loopback ports that the host chose, as in #958's traffic
checks, a clone reaches what its policy allows alone. The host reaches a
listener of the guest at its host-loopback port exactly with
host-loopback access both ways, once the clone's announcer announced it,
and through a forward, and the guest refuses CAP_NET_BIND_SERVICE and
CAP_NET_RAW exactly while the listeners are published. A forward whose
host port another socket holds ends the clone before its restore-ready
event, as a failure of the host, by the evidence of the forward's bind.
The resolver and proxy scenarios now use templates of other networks
than their clones'.

Part of #850

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b459655f-e7a2-4f19-b0b1-9feda7428534
Pedro Henrique Penna (ppenna) added a commit that referenced this pull request Oct 29, 2026
doc/run.md and doc/usage.md said that a sandbox policy that "lets
nothing through" attaches no network device, and listed egress denied
without allow rules, ingress denied, and --host-loopback deny. That is
not the rule that nvx::host::network::openvmm_arguments applies: it
attaches no device exactly when a policy has no proxy, denies egress by
default without allow rules, and denies ingress and host-loopback
access, whatever its deny rules. Both parts of the description were
too broad:

- A policy can let nothing through and still attach a device. A
  sandbox with --network-egress deny and --host-loopback deny renders
  --net and both rules when it also has --network-egress-allow
  192.0.2.1 and --network-egress-deny 192.0.2.0/24, whose deny rule
  covers the allow rule. Through the Rust API, a NetworkPolicy whose
  allow rule excepts its whole destination lowers to no OpenVMM rule
  but attaches a device too, as #1001 reports.
- A proxy-only policy has every option that the documents listed, but
  attaches a device for its proxy.

The documents also did not say which allow rules count. The CLI
compiles a --network-egress-policy-file to native rules before it
builds the policy, so a file whose allow rules all except their whole
destinations leaves no allow rule and attaches no device, while the
same rule in a typed policy of the Rust API counts.

Name the condition by its options in the Sandbox networking section of
doc/run.md, in its note on what changed since earlier releases, and in
the --net row of the sandbox options in doc/usage.md. Say that a policy
file's allow rules are those that it compiles to, that any other policy
attaches a device even if it lets nothing through, and that the typed
policy of the Rust API counts every allow rule.

The issue also offers attaching no device for a policy whose allow
rules lower to no OpenVMM rule. That would change behavior and the
template key of such policies, which the open template stack, #958 and
the pull requests above it, derives from this lowering; #958 even
defines the device of a closed policy as the one that the same policy
gets with one more such rule. So this change keeps the behavior and
documents it.

Fixes #1001.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@esaurez
Enrique Saurez (esaurez) force-pushed the esaurez/846-pr1-export-maps-20261025 branch from 08d111c to e7959b3 Compare October 29, 2026 14:56
@esaurez
Enrique Saurez (esaurez) force-pushed the esaurez/846-pr2-network-templates-20261025 branch from e9e7fc6 to 2a777a3 Compare October 29, 2026 14:56
@esaurez
Enrique Saurez (esaurez) requested a balanced review from Copilot October 29, 2026 14:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues remain for the network-template clone changes.

No open issues 🎉

Review effort: Balanced

Enrique Saurez and others added 2 commits October 29, 2026 08:20
A template's NIC is restored with the network that its capture attached,
so a template serves the clones of that network alone. Until now, a
clone's plan checked only that the template had a NIC when the clone's
plan had a network, at the guest address of that NIC, and the restore
then passed the policy of the clone's own network, which OpenVMM refused
at the restore if it was another.

The template key now holds the network as the capture class lowered it
to OpenVMM's arguments, `--net` with the guest's address, then the
options of the policy, and none for a template without a NIC, so the
no-network identity is shared by a closed network. Its canonical
encoding takes the list as its eighth part and stays version 1: the
encoding has not been released, so a template store that an earlier
build created is not supported, and is deleted and created again, since
nothing migrates it. A key's network must be exactly the arguments to
which a network of a guest at its NIC's address lowers, which decoding
checks by reading the policy back and lowering it again, or none for a
machine without a NIC; the parsers of OpenVMM's native rules, forwards,
and proxy endpoints that it reads with build with the host feature. The
key's vectors of version 1 change in place; the class's, whose encoding
is unchanged, stay as they are.

`ClonePlan` compares the lowering of the adapter's plan's network with
the key's, in one check that replaces the check of the guest's address,
and refuses, before any VMM starts, as a failure of the request with
invalid settings, a network for a template without a NIC, none for a
template with one, and another policy or guest address. The restore
passes the key's network, but `--net` and the address, which OpenVMM
takes from the snapshot, so no clone gets ingress, host-loopback access
to its listeners, or forwards, which no template's policy allows. The
comparison lowers the plan's network, without hashing, and the cold
path, which has no template, is unchanged.

Part of #846

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 34e6ffe3-3ebf-42db-bfca-e0ecfade6873
`runtime-adapter-host start` takes the network of a launch,
`--network FILE`, which it reads before anything else, as a launch
does, and refuses with status 1 if it cannot read it, or if the plan
refuses it. `clone::Request` carries it, and `Request::plan` puts it on
the adapter's plan, which NVX's plan compares with the template's. The
clone's record keeps the plan with its network, so `exec` gives the
clone's executions the URL of the network's proxy, the one that the
clone's activation record names, as it gives a launch's.

In vm_clone, with templates of the networks that a capture takes, the
guest at 192.0.2.2/24:

- A template without a NIC serves clones without a network, and of a
  network that lets nothing through: no network device, no network in
  the record, and the image's own `/etc/resolv.conf`, which no bind
  holds. A clone of each network with a NIC is refused before any VMM
  starts, with status 8 and the record of a failure of the request, at
  the plan, by the evidence of invalid settings.
- A template of each network with a NIC, egress allowed, with outbound
  host-loopback access or without, an allow rule, and a proxy, serves a
  clone of its network, with one network device, on Linux the VMM's
  arguments of the template's policy without `--net`, and a record that
  names the policy, the gateway's DNS server where egress is allowed,
  and the proxy. It refuses each other network, its own policy at
  another guest address, a network that lets nothing through, and none,
  in the same way. The templates' policies differ.
- A clone of a network with egress allowed finds, at `/etc/resolv.conf`,
  a file of mode 0444 that names the gateway's DNS server, held by a
  read-only, nosuid, nodev bind after that of a generated machine ID,
  which a write as root cannot change, and reaches the server: a TCP
  connection to its DNS port opens, which the gateway's DNS proxy
  accepts without the host's resolver. A clone of a disk whose layer
  holds a regular file `etc` ends before it is ready, with status 8, the
  guest's status 57, and the record of a failure of the request, by the
  evidence of invalid settings.
- The executions of a clone of a proxy-only network find the proxy's
  URL in `http_proxy`, `https_proxy`, `HTTP_PROXY`, and `HTTPS_PROXY`,
  after their own entries, and one that names its own keeps its own.
- A clone of a template with a NIC maps its export below the binds of
  its machine ID and of its resolver configuration.

The other scenarios keep templates without a NIC, so their mount tables
hold no resolver configuration.

Part of #846
Part of #845

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 34e6ffe3-3ebf-42db-bfca-e0ecfade6873
@esaurez
Enrique Saurez (esaurez) force-pushed the esaurez/846-pr1-export-maps-20261025 branch from d48bf38 to 551ebda Compare October 29, 2026 15:25
@esaurez
Enrique Saurez (esaurez) force-pushed the esaurez/846-pr2-network-templates-20261025 branch from 2a777a3 to e19ceed Compare October 29, 2026 15:25
Enrique Saurez (esaurez) pushed a commit that referenced this pull request Oct 29, 2026
…in VMs

The VM scenarios of templates and clones tested the interim rule, under
which each network policy had a template of its own, and templates
refused ingress and host-loopback access both ways.

vm_template now creates one template of a network that publishes the
guest's listeners and forwards a port: its key's command line names the
NIC's addresses, but neither a DNS server nor a publication, and the
creation of each other network at the same guest's address serves it
without a capture.

vm_clone starts the clones of every network policy from one template:
each restore installs the clone's own policy, and the clone's record
names its DNS server, proxy, and publication. Through listeners of the
host on host-loopback ports that the host chose, as in #958's traffic
checks, a clone reaches what its policy allows alone. The host reaches a
listener of the guest at its host-loopback port exactly with
host-loopback access both ways, once the clone's announcer announced it,
and through a forward, and the guest refuses CAP_NET_BIND_SERVICE and
CAP_NET_RAW exactly while the listeners are published. A forward whose
host port another socket holds ends the clone before its restore-ready
event, as a failure of the host, by the evidence of the forward's bind.
The resolver and proxy scenarios now use templates of other networks
than their clones'.

Part of #850

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b459655f-e7a2-4f19-b0b1-9feda7428534
@esaurez Enrique Saurez (esaurez) removed their assignment Oct 29, 2026
Base automatically changed from esaurez/846-pr1-export-maps-20261025 to dev October 29, 2026 19:29
@ppenna
Pedro Henrique Penna (ppenna) merged commit 8afc615 into dev Oct 29, 2026
44 checks passed
@ppenna
Pedro Henrique Penna (ppenna) deleted the esaurez/846-pr2-network-templates-20261025 branch October 29, 2026 19:32
Enrique Saurez (esaurez) pushed a commit that referenced this pull request Oct 29, 2026
…in VMs

The VM scenarios of templates and clones tested the interim rule, under
which each network policy had a template of its own, and templates
refused ingress and host-loopback access both ways.

vm_template now creates one template of a network that publishes the
guest's listeners and forwards a port: its key's command line names the
NIC's addresses, but neither a DNS server nor a publication, and the
creation of each other network at the same guest's address serves it
without a capture.

vm_clone starts the clones of every network policy from one template:
each restore installs the clone's own policy, and the clone's record
names its DNS server, proxy, and publication. Through listeners of the
host on host-loopback ports that the host chose, as in #958's traffic
checks, a clone reaches what its policy allows alone. The host reaches a
listener of the guest at its host-loopback port exactly with
host-loopback access both ways, once the clone's announcer announced it,
and through a forward, and the guest refuses CAP_NET_BIND_SERVICE and
CAP_NET_RAW exactly while the listeners are published. A forward whose
host port another socket holds ends the clone before its restore-ready
event, as a failure of the host, by the evidence of the forward's bind.
The resolver and proxy scenarios now use templates of other networks
than their clones'.

Part of #850

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b459655f-e7a2-4f19-b0b1-9feda7428534
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants