Skip to content

nvx-rs: create both guest datagram sockets with UdpSocket::ipv4 - #609

Merged
Pedro Henrique Penna (ppenna) merged 1 commit into
devfrom
nvx-rs-quality/datagram-socket
Oct 19, 2026
Merged

Pedro Henrique Penna (ppenna) merged 1 commit into
devfrom
nvx-rs-quality/datagram-socket

Conversation

@ppenna

Copy link
Copy Markdown
Contributor

Summary

nvx-rs/src/guest/sys/socket.rs creates the guest programs' two close-on-exec IPv4 UDP sockets:

  • connect_datagram, which connects one for the network benchmark of nvx-device-io;
  • UdpSocket::ipv4, the unconnected socket from which nvx-ingress sends its announcements.

connect_datagram spelled out the same socket(AF_INET, SOCK_DGRAM, SOCK_CLOEXEC) call as UdpSocket::ipv4, so the module kept two copies of the socket's family, type, and flags. It now takes its socket from UdpSocket::ipv4, connects it, and returns it as the FileDescriptor that the benchmark reads and writes, as before. The module creates every datagram socket in one place, so the two programs cannot drift apart.

This is the sixth nvx-rs-quality/ pull request. #603, #605, #606, and #607, all merged, and #608, open, had approving Copilot reviews and no other feedback to follow. No nvx-rs-quality/ pull request was closed without merging. Those runs changed protocol/exec.rs, the managed agent, host/filesystem.rs, and the time tools, so this run looked elsewhere. It surveyed the crate by reading and with a throwaway duplicate-window script, and skipped every file that an open pull request to dev changed when it started; #597, #598, and #608 change nvx-rs, and #585 changes aci_edge_sandboxes. It picked this follow-up of #606, #607, and #608 in guest/sys, which no earlier run touched. Of the candidates that the survey found, it removes the most duplicated code per changed line, and existing tests cover both of its paths.

Changes

All changes are in nvx-rs/src/guest/sys/socket.rs: 1 insertion and 6 deletions.

  • connect_datagram gets its socket from UdpSocket::ipv4 instead of its own nix::sys::socket::socket call. Two sites now share that call:
    • connect_datagram, for nvx-device-io network;
    • UdpSocket::ipv4, for nvx-ingress's announcer.

No item, signature, or other file changes.

Behavior

  • Both programs make the same socket and connect system calls, with the same arguments and in the same order, and get the same errno when either fails.
  • A socket whose connect fails still closes when its owner drops, and a connected socket still becomes the same FileDescriptor.
  • Command lines, exit statuses, and byte output of every guest binary are unchanged. The module builds only with the guest feature, so the host and --no-default-features builds do not change.
  • Tests that cover the change:
    • the socket module's tests cover UdpSocket::ipv4;
    • connected_datagrams_wait_for_and_receive_echoes in guest::sys covers connect_datagram;
    • device_io_measures_a_network_round_trip in tests/guest_tools.rs runs the nvx-device-io binary against a local echo server;
    • the microVM suite's private-network-ingress scenario runs nvx-ingress in the guest.

Follow-ups

The survey turned these up, and this change leaves them alone.

  • In guest/sys/spawn.rs, SpawnDescriptors::managed and the test-only SpawnDescriptors::plain differ only in inherit_config. plain could be Self { inherit_config: false, ..Self::managed(...) }.
  • console_pending.rs and mmio_write.rs map each failure with a four-line closure that reports it and returns CommandError::Operation, at seven sites. Reporters that return the error, as ingress::usage and managed_agent::fatal do, would shorten each to one expression; reseed.rs, which Ship nvx-rs in NVX releases #598 changes, has three more.
  • In guest/device_io.rs, run_file and run_network print their measurement the same way; one helper could serve both.
  • In tests/guest_tools.rs, device_io repeats the spawn and output collection of run.
  • These follow-ups of earlier runs also remain:

I found no suspected bug in the code that this change touches.

Validation

  • BASE: 4f5e255b436fecb4950f4aa71319d48e7d18ab43, which was origin/dev when the run started: the merge of nvx-rs: replace the loopback System wrapper with a spawn hook #607. Before this pull request was opened, origin/dev had advanced only by a performance-baseline update, which does not change nvx-rs/src/guest/sys/socket.rs, and no open pull request to dev changed it.

  • TREE: c000e2dc4132dbd274ac30528f5acb6bb6eb0178, the tree of this commit. Every host applied the patch to BASE and checked that git write-tree equals TREE.

  • Release on every host: v0.1.0-dev.da399442504e. BASE has no release yet, so download took the one from two first-parent commits earlier. Its OpenVMM, 5ab8a84621524f1777b2cb5e65a70dab42c8b453, is the pinned revision.

  • Guest artifacts were rebuilt from TREE on prometheus30, with these steps:

    • build-guest-binaries --output;
    • test-guest-binaries --binaries, where 34 tests passed;
    • the Alpine build-initramfs with NVX_GUEST_BINARIES.

    initramfs.cpio.gz (SHA-256 4a4c0597b4bd6ea236a4c57c032d2751bdda504b9fbac01963761c62410a584c), its packages manifest, and its provenance went to the other two hosts, where the SHA-256 digests matched. Building them a second time, after the harness fix below, gave identical digests.

  • Local checks on Windows with Rust 1.95.0:

    • rustfmt;
    • Clippy with -D warnings, for all targets and features and for the library without default features, natively and for x86_64-unknown-linux-gnu, which builds the guest module, and the guest binaries' musl lint for x86_64-unknown-linux-musl;
    • cargo test with all features: 314 library tests, 6 fake-OpenVMM tests, 5 CLI tests, and 1 doctest;
    • the steps that no host could run, because the hosts lack the toolchain or target: the Windows MSRV (1.89) checks and the macOS (aarch64-apple-darwin) checks, for both nvx-rs and aci_edge_sandboxes.
Host profile Backend Host type check-nvx-rs and check-aci-edge-sandboxes without a hypervisor Guest artifacts test-aci-edge-sandboxes test-microvm, default suite
prometheus32 kvm baremetal Pass: every Linux step, including MSRV 1.89, check-guest-binaries (319 tests), 600 nvx-rs tests with all features and 261 with the default ones, 157 and 85 aci_edge_sandboxes tests, artifact bundling, and agent bundling; the macOS checks ran locally Copied in, digests match Pass (18/18) Pass (31 scenario runs)
prometheus30 mshv baremetal None; prometheus32 and prometheus28 ran the gates Built and tested here Pass (18/18) Pass (31 scenario runs)
prometheus28 whp baremetal Pass: every Windows step, including 326 nvx-rs tests with all features and 261 with the default ones, 157 and 85 aci_edge_sandboxes tests, artifact bundling, and agent bundling; the MSRV checks ran locally Copied in, digests match Pass (18/18) Pass (31 scenario runs)

On prometheus32, the first run of the gates failed 5 of the 10 tests in tests/cli.rs, all interrupts:: tests, in which the CLI ignored Ctrl-C: three ended with 0 instead of 130, and in two, Ctrl-C did not end a write to a full pipe. My harness had caused it. It started the gates as a background job of a non-interactive shell, which ignores SIGINT, and the CLI keeps a SIGINT that it starts with ignored, as Python does; the job's mask was SigIgn: 0x7. With the harness fixed to restore the default dispositions (SigIgn: 0), every gate and the guest-artifact build ran again and passed. The change does not touch the CLI.

On prometheus32, the suite's time-ABI evidence line counted 2 of 58 boot checks over KVM's CPU-time budget. The suite reports that count but never gates on it, and this change does not touch the guest's time code. No host fell back to a host CPU profile.

Left to CI:

  • the OpenVMM unit and VMM suites, test-openvmm-unit and test-openvmm;
  • the microVM scenarios that run only when named: smp-lapic, managed-exec-config, and sandbox-lifecycle;
  • the Ubuntu and Azure Linux guests, and guest determinism;
  • the benchmarks;
  • the virtual-machine runners;
  • check-quality and validate-nvx, whose inputs this change does not touch.

guest::sys::socket creates two close-on-exec IPv4 UDP sockets: the one
that connect_datagram connects for nvx-device-io's network benchmark,
and the unconnected UdpSocket from which nvx-ingress sends its
announcements. connect_datagram spelled out the same socket(AF_INET,
SOCK_DGRAM, SOCK_CLOEXEC) call as UdpSocket::ipv4, so the module kept
two copies of the socket's family, type, and flags.

connect_datagram now takes its socket from UdpSocket::ipv4, connects
it, and returns it as the FileDescriptor that the benchmark reads and
writes, as before. The module creates every datagram socket in one
place, so the two programs cannot drift apart.

Behavior is unchanged. Both programs make the same socket and connect
system calls, with the same arguments and in the same order, and get
the same errno when either fails. A socket whose connect fails still
closes when its owner drops. The change is confined to the guest
binaries' system layer, which only the guest feature builds.

The socket module's tests cover UdpSocket::ipv4, the system layer's
connected_datagrams_wait_for_and_receive_echoes covers
connect_datagram, and the guest-tool test
device_io_measures_a_network_round_trip runs the nvx-device-io binary
against a local echo server.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 19, 2026 18:58

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

The narrow refactor preserves behavior, existing tests cover both paths, and no unresolved issues remain.

No open issues 🎉

What changed in this PR

Centralizes guest IPv4 UDP socket creation, completing a cleanup identified in earlier refactors.

Changes:

  • Reuses UdpSocket::ipv4 in connect_datagram.
  • Preserves connection handling and the returned FileDescriptor.
File Description
nvx-rs/​src/​guest/​sys/​socket.rs Removes duplicate socket creation in favor of the existing constructor.

Review effort: Balanced

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.

2 participants