Repository navigation
consomme: present IPv6 host peers inside the static subnet - #135
Merged
Merged
Conversation
Part of microsoft/nvx#276. Consomme presents a host-local peer, such as host loopback, to the guest at a virtual address, so that the guest replies through its NIC. IPv4 peers get an address inside the guest's subnet, but IPv6 peers got a link-local address. A guest answers a link-local peer from its own link-local address: TCP replies from the address that a SYN reached, but UDP servers on a wildcard socket choose their source address for the destination. Under a static IPv6 identity, whose egress policy admits only the guest's address in the subnet as a source, the UDP reply of a guest service to a host client on IPv6 loopback was therefore dropped whenever a policy was active, as under egress deny. Under a static IPv6 identity, allocate those virtual addresses inside the static subnet instead, downward from its last address, which IPv6 does not reserve for broadcast, skipping the gateway and the guest: fd00::a00:ff beside 10.0.0.254. Even the /126 that a /30 IPv4 network derives thus keeps an address for a host peer. The guest then answers from its address in the subnet, and resolves the peer like any neighbor there. create_virtual_address follows suit, so a host address keeps one virtual address. Endpoints without a static IPv6 identity keep link-local addresses. The link-local cases that served the old addresses go: the gateway no longer answers Neighbor Solicitations for link-local virtual addresses, and an egress policy that allows ingress no longer admits Neighbor Solicitations for link-local targets. Cover the allocation, including the smallest static subnet, the presentation and resolution of an IPv6 host peer, and the tightened policy with tests, and update the Guide. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ppenna
added a commit
to microsoft/nvx
that referenced
this pull request
Oct 13, 2026
Pin nanvix/openvmm#135 at 7f225e2cd635bbd1e1839e587e659996433396c8, one commit on a44fcc2a. OpenVMM presented host-loopback peers to the guest at link-local IPv6 addresses, and a guest UDP server answered them from its own link-local address, which the egress policy rejects as a source. A host client on ::1 therefore got no UDP reply whenever an egress policy was active, such as under egress deny. Under the static IPv6 identity, OpenVMM now presents IPv6 host peers inside the guest's subnet, as it presents IPv4 ones, so the guest answers from its address there. Index the new pin in the roadmap and update the network ABI description. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
4 open findings
next_ipv6_offset_from_endis au8, which hard-limits subnet-based IPv6 virtual address… · New This logic treats integer overflow ofnext_ipv6_offset_from_endas pool exhaustion… · New The guide text reads as unconditional, but the implementation keeps IPv6 host peers link-local when… · New The allocation-strategy selection (gateway_ipv6+client_ip_ipv6_routable=> subnet allocation… · New
What changed in this PR
Updates Consomme’s IPv6 host-peer presentation so host loopback peers appear inside the guest’s static IPv6 subnet (instead of link-local), fixing UDP reply behavior under egress policies like --network-egress deny.
Changes:
- Allocate IPv6 host-peer virtual addresses from the high end of the static IPv6 subnet (skipping gateway/guest), and update flow / virtual address creation to match.
- Remove NDP/egress-policy special-cases that existed solely to support link-local host-peer virtual addresses.
- Extend/update tests and documentation to validate and describe the new IPv6 behavior (including smallest
/126subnet).
| File | Description |
|---|---|
| vm/devices/net/net_consomme/consomme/src/tests/static_ipv6.rs | Updates static IPv6 tests to assert host peers are allocated inside the static subnet; adds coverage for /126. |
| vm/devices/net/net_consomme/consomme/src/ndp.rs | Removes NDP on-link handling for legacy link-local virtual host-peer addresses. |
| vm/devices/net/net_consomme/consomme/src/local_addr_map.rs | Adds allocation of host-peer IPv6 virtual addresses inside the static subnet from the high end; adds unit tests. |
| vm/devices/net/net_consomme/consomme/src/lib.rs | Switches IPv6 local peer mapping and create_virtual_address to prefer static-subnet allocation when available. |
| vm/devices/net/net_backend_resources/src/egress/ipv6/tests.rs | Updates egress-policy tests for new subnet-based host-peer addressing and removes legacy link-local expectations. |
| vm/devices/net/net_backend_resources/src/egress/ipv6.rs | Simplifies ingress resolvability logic to only consider on-link (subnet) neighbors for NDP. |
| Guide/src/reference/backends/consomme.md | Updates docs to explain subnet-based host-peer virtual addresses and rationale for correct UDP behavior. |
🧠 Review effort: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| /// Next available IPv6 host offset from the end of a static IPv6 subnet, | ||
| /// counting downward from 1 for its last address, which IPv6, unlike | ||
| /// IPv4, does not reserve for broadcast. | ||
| next_ipv6_offset_from_end: u8, |
Comment on lines
+219
to
+227
| if self.next_ipv6_offset_from_end == 0 { | ||
| tracelimit::warn_ratelimited!( | ||
| real_addr = %real_addr, | ||
| "Local IPv6 virtual address pool exhausted" | ||
| ); | ||
| return None; | ||
| } | ||
| let offset_from_end = self.next_ipv6_offset_from_end; | ||
| self.next_ipv6_offset_from_end = offset_from_end.checked_add(1).unwrap_or(0); |
Comment on lines
+109
to
+114
| family, allocated downward from its high end, so that the guest answers them | ||
| from its address in that subnet. The endpoint's egress policy evaluates the | ||
| guest's traffic to such an address at the host address to which Consomme | ||
| routes it, and for host loopback at the gateway of its family, so a peer's | ||
| virtual address reaches no host-loopback port that the rules deny at the | ||
| gateway. Without ingress `allow`, OpenVMM appends |
Comment on lines
+545
to
+562
| // A static IPv6 identity's subnet is on link, as the IPv4 | ||
| // subnet is, so a host peer presented there is answered from | ||
| // the guest's address in it, which a link-local peer would | ||
| // not be. | ||
| let virtual_ip = match (params.gateway_ipv6, params.client_ip_ipv6_routable) { | ||
| (Some(gateway), Some(client)) => local_addr_map.get_or_allocate_v6_in_subnet( | ||
| *v6.ip(), | ||
| gateway, | ||
| params.prefix_len_ipv6, | ||
| client, | ||
| ), | ||
| _ => local_addr_map.get_or_allocate_v6( | ||
| *v6.ip(), | ||
| params.gateway_link_local_ipv6, | ||
| params.client_ip_ipv6, | ||
| params.client_ip_ipv6_routable, | ||
| ), | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
Host-to-guest UDP over IPv6 loopback failed whenever a microVM egress policy was active, for example under
--network-egress deny. Consomme presented IPv6 host peers to the guest at link-local virtual addresses (fe80::ff:fe00:N:1), and a guest UDP server on a wildcard socket answers a link-local peer from its own link-local address, which the egress policy rejects as a source. TCP was unaffected because it replies from the address that the SYN reached. IPv4 host peers already appear inside the guest's subnet.fd00::a00:ffbeside10.0.0.254. IPv6 has no broadcast address, so even the/126that a/30IPv4 network derives keeps an address for a host peercreate_virtual_addressfollows suit, so one host address keeps one virtual address; endpoints without a static IPv6 identity keep link-local addressesPart of microsoft/nvx#276; follows #134.
Revision
7f225e2cd635bbd1e1839e587e659996433396c8, one SSH-signed commit directly onmainata44fcc2aa496cc9b50b15d3e593d02e27e04a4fbValidation
On Windows:
cargo clippy --all-targetsforconsomme,net_consomme, andnet_backend_resources: no lintscargo doc --no-depswith-D warningsfor the same packagescargo nextest run --profile agentfornet_backend_resources,consomme,net_consomme,openvmm_defs, andopenvmm_entry: 476 passedcargo xtask fmt --fix: clean::1gets the guest's reply under egress deny, which failed before this commit; thehost-loopback-policyscenario, extended in Support bidirectional host-loopback access microsoft/nvx#512 with an IPv6 UDP exchange, passes with this commit and fails witha44fcc2a("guest UDP server did not answer through ::1");private-network-ingress,ipv6-egress-policy,directional-network-policy,network-snapshot, andendpoint-policy-snapshotpass; the ACI Edge Sandboxes end-to-end suite passes 18/18