Skip to content

openvmm_entry/ttrpc: expose PCIe NUMA and ACS config#4009

Draft
jstarks wants to merge 6 commits into
microsoft:mainfrom
jstarks:ttrpc-generic-initiator-acs
Draft

openvmm_entry/ttrpc: expose PCIe NUMA and ACS config#4009
jstarks wants to merge 6 commits into
microsoft:mainfrom
jstarks:ttrpc-generic-initiator-acs

Conversation

@jstarks

@jstarks jstarks commented Jul 23, 2026

Copy link
Copy Markdown
Member

GB200-style device topologies need the management interface to describe PCIe devices as ACPI Generic Initiators and control the ACS capabilities advertised by individual ports. Extend the VM service schema and topology conversion so these settings reach the canonical OpenVMM configuration.

Use pipette in the ttrpc integration test to verify the resulting SRAT Generic Initiator entry and ACS capability directly from inside the guest.

GB200-style device topologies need the management interface to describe
PCIe devices as ACPI Generic Initiators and control the ACS capabilities
advertised by individual ports. Extend the VM service schema and topology
conversion so these settings reach the canonical OpenVMM configuration.

Use pipette in the ttrpc integration test to verify the resulting SRAT
Generic Initiator entry and ACS capability directly from inside the guest.
Copilot AI review requested due to automatic review settings July 23, 2026 10:36
@jstarks
jstarks requested a review from a team as a code owner July 23, 2026 10:36

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.

Pull request overview

This PR extends the OpenVMM ttrpc VM service schema and its openvmm_entry conversion layer to support (1) PCIe NUMA “Generic Initiator” descriptions and (2) per-port ACS capability advertisement, and adds a VMM integration test that validates both behaviors from inside the guest using pipette.

Changes:

  • Extend vmservice.proto with PcieGenericInitiator and PciePort.acs_capabilities_supported.
  • Plumb the new schema fields through openvmm_entry topology conversion into the canonical openvmm_defs::config.
  • Enhance the ttrpc VMM test to inject pipette into the initrd and validate SRAT GI affinity + ACS capability in-guest.

Reviewed changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
vmm_tests/vmm_tests/tests/tests/ttrpc.rs Injects pipette into the guest initrd, enables hvsocket for one VM instance, configures ACS + GI, and validates SRAT/PCIe config from inside the guest.
vmm_tests/vmm_tests/Cargo.toml Adds initrd_cpio dependency for initrd injection in the test.
openvmm/openvmm_ttrpc_vmservice/src/vmservice.proto Adds schema support for PCIe Generic Initiators and per-port ACS capability configuration.
openvmm/openvmm_entry/src/ttrpc/mod.rs Threads new PCIe schema fields into openvmm_defs::config via a flattened BuiltPcieTopology.
Cargo.lock Locks the new initrd_cpio dependency.
Comments suppressed due to low confidence (2)

vmm_tests/vmm_tests/tests/tests/ttrpc.rs:866

  • This unwrap() can panic if the slice length is wrong; prefer propagating a contextual error so failures are reported cleanly (especially when debugging guest PCI config parsing).
            config
                .get(capability_offset..capability_offset + 4)
                .context("invalid PCIe extended capability offset")?
                .try_into()
                .unwrap(),

vmm_tests/vmm_tests/tests/tests/ttrpc.rs:885

  • This unwrap() can panic on unexpected config layout. Using context(...)? here will keep the test failure in the anyhow error path with a clearer message.
        config
            .get(acs_offset + 4..acs_offset + 6)
            .context("parent port has no ACS capability register")?
            .try_into()
            .unwrap(),

Comment on lines +826 to +832
let proximity_domain =
u32::from_le_bytes(srat[offset + 4..offset + 8].try_into().unwrap());
let entry_segment =
u16::from_le_bytes(srat[offset + 8..offset + 10].try_into().unwrap());
let entry_bus = srat[offset + 10];
let entry_devfn = srat[offset + 11];
let flags = u32::from_le_bytes(srat[offset + 24..offset + 28].try_into().unwrap());
message PcieTopologyConfig {
// The PCIe root complexes in the VM.
repeated PcieRootComplex root_complexes = 1;
// Devices that act as initiators for device-only NUMA nodes.
Copilot AI review requested due to automatic review settings July 23, 2026 10:53

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.

Pull request overview

Copilot reviewed 4 out of 5 changed files in this pull request and generated no new comments.

@github-actions

Copy link
Copy Markdown

@jstarks
jstarks marked this pull request as draft July 24, 2026 09:56
Copilot AI review requested due to automatic review settings July 24, 2026 09:56

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.

Pull request overview

Copilot reviewed 5 out of 6 changed files in this pull request and generated 2 comments.

Comment on lines +62 to +65
let pipette_initrd = initrd_cpio::inject_into_initrd(&initrd, "pipette", &pipette, 0o100755)
.context("failed to inject pipette into test initrd")?;
let mut pipette_initrd_file = tempfile::NamedTempFile::new()?;
pipette_initrd_file.write_all(&pipette_initrd)?;
Comment on lines +535 to +547
if let Some(listener) = pipette_listener {
let mut listener = PolledSocket::new(&driver, listener)?;
let (conn, _) = listener.accept().await?;
let conn = PolledSocket::new(&driver, conn)?;
let agent = pipette_client::PipetteClient::new(
&driver,
conn,
params.logger.output_dir(),
)
.await?;
validate_pcie_config(&agent).await?;
agent.power_off().await?;
}
@jstarks
jstarks force-pushed the ttrpc-generic-initiator-acs branch from d806e1c to 09f26e6 Compare July 24, 2026 11:11
Copilot AI review requested due to automatic review settings July 24, 2026 11:11

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.

Pull request overview

Copilot reviewed 5 out of 6 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

vmm_tests/vmm_tests/tests/tests/ttrpc.rs:539

  • listener.accept().await has no timeout, so if the guest fails to start pipette (or HvSocket wiring breaks) this test can hang indefinitely in CI. Add an explicit deadline around the accept and fail with a clear error message on timeout.
                    if let Some(listener) = pipette_listener {
                        let mut listener = PolledSocket::new(&driver, listener)?;
                        let (conn, _) = listener.accept().await?;
                        let conn = PolledSocket::new(&driver, conn)?;
                        let agent = pipette_client::PipetteClient::new(

Copilot AI review requested due to automatic review settings July 24, 2026 11:36

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.

Pull request overview

Copilot reviewed 6 out of 7 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

vmm_tests/vmm_tests/tests/tests/ttrpc.rs:66

  • pipette_initrd_file is created with NamedTempFile::new(), which places it in the global temp directory rather than under tempdir. This contradicts the comment above that all temporary files for the test live under a single temp directory, and also makes it harder to correlate artifacts when debugging failures.

Create the file inside tempdir with NamedTempFile::new_in(tempdir.path()) (or update the comment if the intent is to allow temp files elsewhere).

    let pipette_initrd = initrd_cpio::inject_into_initrd(&initrd, "pipette", &pipette, 0o100755)
        .context("failed to inject pipette into test initrd")?;
    let mut pipette_initrd_file = tempfile::NamedTempFile::new()?;
    pipette_initrd_file.write_all(&pipette_initrd)?;

Copilot AI review requested due to automatic review settings July 24, 2026 11:44

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.

Pull request overview

Copilot reviewed 7 out of 8 changed files in this pull request and generated 1 comment.

// graph to the log so VM state is captured for
// post-mortem diagnosis even when no client is
// attached to inspect it.
self.dump_inspect_graph().await;
Copilot AI review requested due to automatic review settings July 24, 2026 11: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.

Pull request overview

Copilot reviewed 8 out of 9 changed files in this pull request and generated no new comments.

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