Skip to content

feat(machine-a-tron): simulate WIWYNN GB200 racks - #4422

Open
poroh wants to merge 2 commits into
NVIDIA:mainfrom
poroh:feature/simulate-wiwynn-gb200-rack
Open

feat(machine-a-tron): simulate WIWYNN GB200 racks#4422
poroh wants to merge 2 commits into
NVIDIA:mainfrom
poroh:feature/simulate-wiwynn-gb200-rack

Conversation

@poroh

@poroh poroh commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

This PR adds first-class simulation of a WIWYNN GB200 NVL72 rack in machine-a-tron.

Previously, machine-a-tron could simulate the individual hardware components but did not understand a rack as an atomic hardware model. This made it difficult to register an expected rack in Carbide and simulate all devices at their correct rack positions.

The new rack model is defined in bmc-mock and uses the NVIDIA GB200 rack design with WIWYNN compute trays, NVIDIA ND5200 NVLink switch trays, and LiteOn power shelves. Machine-a-tron expands each configured rack into its devices, registers the expected rack using its configured rack_profile_id, and reports the devices through the rack and machine status endpoints.

Rack-specific configuration uses a tagged model enum, keeping WIWYNN fields isolated and allowing future rack types without adding their settings to every RackConfig. Expected-rack registration and device creation also use the same resolved rack representation to avoid configuration drift.

This change intentionally supports only the WIWYNN GB200 NVL72 rack. Standalone machine configuration remains available for custom hardware combinations.

Related issues

Type of Change

  • Add - New feature or capability
  • Change - Changes in existing functionality
  • Fix - Bug fixes
  • Remove - Removed features or deprecated functionality
  • Internal - Internal changes (refactoring, tests, docs, etc.)

Breaking Changes

  • This PR contains breaking changes

Testing

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing performed
  • No testing required (docs, internal refactor, etc.)

Additional Notes

The rack profile itself remains owned by Carbide. Machine-a-tron accepts the rack_profile_id to assign when registering each expected rack; it does not redefine or reconfigure that profile.

Signed-off-by: Dmitry Porokh <dporokh@nvidia.com>
@poroh
poroh requested a review from a team as a code owner July 31, 2026 00:23
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Summary by CodeRabbit

  • New Features

    • Added support for configuring and simulating Wiwynn GB200 NVL72 racks, including rack members, hardware positions, and associated machines.
    • Added rack status endpoints for viewing all racks or retrieving an individual rack, including member device statuses.
    • Added validation for rack identifiers, profiles, duplicate assignments, and configuration conflicts.
  • Documentation

    • Updated configuration examples with concrete NVL72 rack settings and networking details.
  • Tests

    • Added comprehensive rack integration and status coverage.

Walkthrough

Changes

Rack lifecycle

Layer / File(s) Summary
Rack hardware model
crates/bmc-mock/src/hw/*, crates/bmc-mock/src/{lib.rs,rack_info.rs}
Adds rack elevation types, Wiwynn GB200 NVL72 hardware modeling, rack type metadata, and elevation resolution.
Configuration expansion and wiring
crates/machine-a-tron/src/config.rs, crates/machine-a-tron/src/{rack.rs,lib.rs,machine_a_tron.rs}, crates/machine-a-tron/config/mat.toml
Adds typed rack groups, validation, deterministic machine/rack expansion, resolved device configurations, and rack registration wiring.
Simulator registry and status endpoints
crates/machine-a-tron/src/{simulator_registry.rs,control_router.rs}, crates/machine-a-tron/src/{device_handle.rs,host_machine.rs}
Registers rack members with simulators and exposes aggregate and individual rack status responses with routing tests.
Rack integration validation
crates/api-integration-tests/tests/{rack.rs,lib.rs}
Adds NVL72 end-to-end assertions and simplifies existing machine-only integration tests to use an empty rack configuration.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Config
  participant MachineATron
  participant SimulatorRegistry
  participant ControlRouter
  participant APIClient
  Config->>MachineATron: resolve rack configuration
  MachineATron->>SimulatorRegistry: register resolved machines and racks
  APIClient->>ControlRouter: request rack status
  ControlRouter->>SimulatorRegistry: retrieve rack status
  SimulatorRegistry-->>ControlRouter: return member device statuses
  ControlRouter-->>APIClient: serialize rack status response
Loading

Suggested labels: rack lifecycle

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.58% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the primary change: adding WIWYNN GB200 rack simulation to machine-a-tron.
Description check ✅ Passed The description accurately explains the rack simulation model, configuration, endpoints, supported hardware, and testing scope.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🧹 Nitpick comments (5)
crates/api-integration-tests/tests/rack.rs (1)

110-156: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract shared MachineATronConfig defaults to avoid duplicated boilerplate. Both files build a near-identical ~20-field literal (dhcp, log_file, bmc_mock_port, interface, tui_enabled, use_single_bmc_mock, configure_carbide_bmc_proxy_host, persist_dir, cleanup_on_quit, register_expected_machines, host_bmc_password, dpu_bmc_password, api_refresh_interval, mock_bmc_ssh_server, mock_bmc_ssh_port, enable_ipmi_simulation, hw_mac_address_ranges, mac_address_pool) for every test-harness invocation.

  • crates/api-integration-tests/tests/rack.rs#L110-L156: replace the inline literal's shared defaults with a common constructor/builder call, keeping only the rack-specific racks/machines/carbide_api_url fields inline.
  • crates/api-integration-tests/tests/lib.rs#L1371-L1419: same — factor the identical defaults into the shared constructor so both harnesses consume one source of truth for test-harness defaults.

As per coding guidelines, "builders mainly for large configurations with optional/defaultable fields" — MachineATronConfig qualifies given most of its fields already carry #[serde(default = ...)].

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/api-integration-tests/tests/rack.rs` around lines 110 - 156, Add a
shared constructor or builder for MachineATronConfig defaults, then update
crates/api-integration-tests/tests/rack.rs:110-156 and
crates/api-integration-tests/tests/lib.rs:1371-1419 to use it, keeping only each
harness’s racks, machines, and carbide_api_url overrides inline. Ensure both
sites consume the same defaults for all listed shared fields.

Source: Coding guidelines

crates/machine-a-tron/src/rack.rs (1)

40-52: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Document that device_index is registry-relative.

RackMemberRef is only meaningful against the SimulatorRegistry device vector that produced it. A one-line doc comment removes the ambiguity for future callers.

📝 Suggested addition
 #[derive(Clone, Debug)]
 pub(crate) struct RackMemberRef {
     pub position: u8,
+    /// Index into the owning `SimulatorRegistry` device list; not valid across registries.
     pub device_index: usize,
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/machine-a-tron/src/rack.rs` around lines 40 - 52, Add a one-line doc
comment to the device_index field in RackMemberRef stating that it is an index
relative to the SimulatorRegistry device vector that produced the reference.
crates/machine-a-tron/src/config.rs (2)

493-497: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Prefer a fallible error over expect in a config-resolution path.

resolved_device_configs already returns eyre::Result, so an unsupported rack hardware type should surface as a configuration error rather than a panic. The current invariant is only enforced by the elevation test in crates/bmc-mock/src/hw/wiwynn_gb200_nvl72_rack.rs; a future rack model could silently introduce a panic here.

♻️ Proposed change
-                let dpu_per_host_count = unit
-                    .hardware_type
-                    .fixed_number_of_dpu()
-                    .expect("rack hardware must have a fixed number of DPUs")
-                    .into();
+                let dpu_per_host_count = u32::from(
+                    unit.hardware_type.fixed_number_of_dpu().ok_or_else(|| {
+                        eyre::eyre!(
+                            "rack {rack_id} unit {} ({}) has no fixed DPU count",
+                            unit.position,
+                            unit.hardware_type
+                        )
+                    })?,
+                );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/machine-a-tron/src/config.rs` around lines 493 - 497, Update the
config-resolution logic containing dpu_per_host_count to propagate
fixed_number_of_dpu() failure through the existing eyre::Result returned by
resolved_device_configs, replacing the panic-producing expect. Preserve the
successful conversion to the DPU count while returning a configuration error for
unsupported rack hardware types.

Source: Coding guidelines


141-211: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Rack simulation settings duplicate MachineConfig field-for-field.

Thirteen fields plus a 28-line manual mapper now mirror MachineConfig (lines 72-132). Any future simulation knob must be added in three places, and the test helper wiwynn_gb200_rack_from_machine exists purely to bridge the two shapes. Extracting the shared block into one flattened struct keeps the TOML wire format identical while eliminating the mapper.

♻️ Sketch
#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
pub struct SimulationSettings {
    pub dpu_reboot_delay: u64,
    pub host_reboot_delay: u64,
    // ... remaining shared fields with their existing serde attributes
}

pub struct MachineConfig {
    #[serde(flatten)]
    pub simulation: SimulationSettings,
    // machine-only fields: rack_id, hw_type, host_count, ...
}

pub struct WiwynnGb200RackConfig {
    #[serde(flatten)]
    pub simulation: SimulationSettings,
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/machine-a-tron/src/config.rs` around lines 141 - 211, Extract the
duplicated simulation fields and their existing serde attributes from
MachineConfig and WiwynnGb200RackConfig into a shared SimulationSettings struct.
Flatten this struct into both configurations to preserve the current TOML wire
format, and update component_machine_config and all field accesses to use the
shared settings. Remove the manual field-by-field mapper and adjust
wiwynn_gb200_rack_from_machine and related construction code to reuse
SimulationSettings directly.

Source: Coding guidelines

crates/bmc-mock/src/hw/nvidia_gb200.rs (1)

24-28: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Three adjacent HardwareType parameters invite silent transposition.

The signature declares compute_tray, power_shelf, nvlink_switch_tray while the body populates compute → switch → shelf. Since all three share a type, a swapped call site compiles cleanly and yields a wrong elevation. Consider a small named-field parameter struct so callers cannot mis-order it.

♻️ Suggested parameter struct
pub(crate) struct Nvl72Trays {
    pub compute_tray: HardwareType,
    pub nvlink_switch_tray: HardwareType,
    pub power_shelf: HardwareType,
}

pub(crate) fn nvl72_rack_elevation(trays: Nvl72Trays) -> RackElevation { /* ... */ }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/bmc-mock/src/hw/nvidia_gb200.rs` around lines 24 - 28, Replace the
three positional HardwareType parameters of nvl72_rack_elevation with a named
Nvl72Trays struct containing compute_tray, nvlink_switch_tray, and power_shelf
fields, then update the function body and all call sites to access or initialize
those fields by name while preserving the existing elevation behavior.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/machine-a-tron/config/mat.toml`:
- Around line 85-98: Update the commented standalone rack_id example in the
[machines.config] section to use a rack identifier distinct from the atomic rack
IDs shown in [racks.default], while preserving the existing example structure
and explanatory comments.

---

Nitpick comments:
In `@crates/api-integration-tests/tests/rack.rs`:
- Around line 110-156: Add a shared constructor or builder for
MachineATronConfig defaults, then update
crates/api-integration-tests/tests/rack.rs:110-156 and
crates/api-integration-tests/tests/lib.rs:1371-1419 to use it, keeping only each
harness’s racks, machines, and carbide_api_url overrides inline. Ensure both
sites consume the same defaults for all listed shared fields.

In `@crates/bmc-mock/src/hw/nvidia_gb200.rs`:
- Around line 24-28: Replace the three positional HardwareType parameters of
nvl72_rack_elevation with a named Nvl72Trays struct containing compute_tray,
nvlink_switch_tray, and power_shelf fields, then update the function body and
all call sites to access or initialize those fields by name while preserving the
existing elevation behavior.

In `@crates/machine-a-tron/src/config.rs`:
- Around line 493-497: Update the config-resolution logic containing
dpu_per_host_count to propagate fixed_number_of_dpu() failure through the
existing eyre::Result returned by resolved_device_configs, replacing the
panic-producing expect. Preserve the successful conversion to the DPU count
while returning a configuration error for unsupported rack hardware types.
- Around line 141-211: Extract the duplicated simulation fields and their
existing serde attributes from MachineConfig and WiwynnGb200RackConfig into a
shared SimulationSettings struct. Flatten this struct into both configurations
to preserve the current TOML wire format, and update component_machine_config
and all field accesses to use the shared settings. Remove the manual
field-by-field mapper and adjust wiwynn_gb200_rack_from_machine and related
construction code to reuse SimulationSettings directly.

In `@crates/machine-a-tron/src/rack.rs`:
- Around line 40-52: Add a one-line doc comment to the device_index field in
RackMemberRef stating that it is an index relative to the SimulatorRegistry
device vector that produced the reference.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: ed15e692-2fb5-4acd-a113-2793f7de4967

📥 Commits

Reviewing files that changed from the base of the PR and between 395a11f and dc44cf7.

📒 Files selected for processing (17)
  • crates/api-integration-tests/tests/lib.rs
  • crates/api-integration-tests/tests/rack.rs
  • crates/bmc-mock/src/hw/mod.rs
  • crates/bmc-mock/src/hw/nvidia_gb200.rs
  • crates/bmc-mock/src/hw/rack.rs
  • crates/bmc-mock/src/hw/wiwynn_gb200_nvl72_rack.rs
  • crates/bmc-mock/src/lib.rs
  • crates/bmc-mock/src/rack_info.rs
  • crates/machine-a-tron/config/mat.toml
  • crates/machine-a-tron/src/config.rs
  • crates/machine-a-tron/src/control_router.rs
  • crates/machine-a-tron/src/device_handle.rs
  • crates/machine-a-tron/src/host_machine.rs
  • crates/machine-a-tron/src/lib.rs
  • crates/machine-a-tron/src/machine_a_tron.rs
  • crates/machine-a-tron/src/rack.rs
  • crates/machine-a-tron/src/simulator_registry.rs

Comment on lines +85 to 98
# [racks.default]
# type = "wiwynn_gb200_nvl72"
# rack_profile_id = "NVL72"
# ids = ["rack-001", "rack-002"]
# dpu_reboot_delay = 20
# host_reboot_delay = 10
# oob_dhcp_relay_address = "192.168.192.1"
# admin_dhcp_relay_address = "192.168.176.1"
# host_inband_dhcp_relay_address = "192.168.177.1"

[machines.config]
# Standalone devices can share any rack ID. They cannot be added to one of the
# atomic racks declared above.
# rack_id = "rack-001"

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

The two examples conflict if both are uncommented.

ids = ["rack-001", "rack-002"] and the standalone rack_id = "rack-001" below cannot coexist: validation rejects standalone devices targeting an atomic rack. Using a distinct ID in the standalone example makes the sample config copy-paste safe.

🩹 Suggested tweak
-# rack_id = "rack-001"
+# rack_id = "rack-100"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# [racks.default]
# type = "wiwynn_gb200_nvl72"
# rack_profile_id = "NVL72"
# ids = ["rack-001", "rack-002"]
# dpu_reboot_delay = 20
# host_reboot_delay = 10
# oob_dhcp_relay_address = "192.168.192.1"
# admin_dhcp_relay_address = "192.168.176.1"
# host_inband_dhcp_relay_address = "192.168.177.1"
[machines.config]
# Standalone devices can share any rack ID. They cannot be added to one of the
# atomic racks declared above.
# rack_id = "rack-001"
# [racks.default]
# type = "wiwynn_gb200_nvl72"
# rack_profile_id = "NVL72"
# ids = ["rack-001", "rack-002"]
# dpu_reboot_delay = 20
# host_reboot_delay = 10
# oob_dhcp_relay_address = "192.168.192.1"
# admin_dhcp_relay_address = "192.168.176.1"
# host_inband_dhcp_relay_address = "192.168.177.1"
[machines.config]
# Standalone devices can share any rack ID. They cannot be added to one of the
# atomic racks declared above.
# rack_id = "rack-100"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/machine-a-tron/config/mat.toml` around lines 85 - 98, Update the
commented standalone rack_id example in the [machines.config] section to use a
rack identifier distinct from the atomic rack IDs shown in [racks.default],
while preserving the existing example structure and explanatory 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.

1 participant