Skip to content

Sled-agent: detect switch backend (tofino, softnpu, et al) at runtime - #11237

Open
sion42x wants to merge 6 commits into
mainfrom
skaram/detect-softnpu
Open

Sled-agent: detect switch backend (tofino, softnpu, et al) at runtime#11237
sion42x wants to merge 6 commits into
mainfrom
skaram/detect-softnpu

Conversation

@sion42x

@sion42x sion42x commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Replace the switch-asic, switch-stub, and switch-softnpu cargo features with startup detection. A Tofino node in the device tree selects the Tofino ASIC; otherwise a virtio 9p device answering 9P2000.P4 selects the propolis SoftNPU backend, and with neither the existing auto Tofino path is used. Optional switch_backend config added for the stub and SoftNPU zone backends. pumpkind is gated on Oxide hardware.

This PR is a proposed solution to #11202 based on feedback from the control plane team. Prior proposed/attempted solutions:

  1. Don't detect, just publish the softnpu sled-agent with CI as a downloadable artifact: Publish the omicron-sled-agent package as a separate artifact for dev labs #11133 (half measure and doesn't solve the real issue)
  2. Extending SMBIOS Type 1 table to label the device (results in a new propolis API version, overkill)
  3. Creation of a named pci device in propolis for softnpu (probably unnecessary, read on)
  4. Detection of the existing vio9p device based on a new subsystem ID (breaks driver loading due to illumos device binding and scadm hardcoding, likewise Mode::Modern requires newer stlouis changes and would be the first modern-only device)

Options 2-4 would have also required additional tooling in omicron to detect these things, making it a pretty sizeable cross-repo change. However, @rcgoodfellow proposed a detection method scadm already uses:

  • look for p9fs devices using devinfo
  • ask the p9 server if it is 9P2000.P4
  • profit

So rather than changing propolis, this PR uses that method to detect softnpu devices. A test on a racklette vs on a voxel lab showed:

Rack Sleds Detection log pumpkind Dendrite
madrid 14, 16 found tofino node imported, online /dev/tofino/1
madrid 15, 17 none imported, online n/a
voxel g0, g2 found SoftNPU 9p device skipped, no instance switch0 online
voxel g1 none skipped, no instance n/a

Lastly, follow ups:

  • sled_mode, sidecar_revision, and switch_backend overlap, and legal combinations are enforced by runtime checks. It would probably be good to get the latter two into one switch enum so illegal configs aren't representable.
  • Switch zone contents are still chosen at build time, but dendrite has an issue for that: One build multiple ASICs dendrite#355

Replace the switch-asic, switch-stub, and switch-softnpu cargo features
with startup detection. The propolis SoftNPU backend is selected by a
virtio 9p device answering 9P2000.P4; without one the existing Tofino
path is used. Optional switch_backend config added for the stub and
SoftNPU zone backends. pumpkind is gated on Oxide hardware.
@sion42x

sion42x commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

Note for reviewers: I realized detect_switch_hardware should just use get_tofino_snapshot. The latter requires node.has_asic() and they both resolve identically downstream (TofinoView::Real either way), but folding it into one pre-existing surface makes more sense. I'm working on that now.

Comment thread sled-agent/src/bootstrap/pre_server.rs Outdated
Comment thread sled-agent/src/bootstrap/pre_server.rs Outdated
Comment thread sled-agent/src/bootstrap/pre_server.rs Outdated
Comment thread sled-hardware/src/softnpu.rs Outdated
Comment thread sled-hardware/src/softnpu.rs
Comment thread sled-hardware/src/illumos/softnpu.rs Outdated
devinfo: &mut DevInfo,
) -> Result<Option<String>, SwitchDetectError> {
let mut walker = devinfo.walk_node();
while let Some(node) =

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.

This loop kinda-sorta feels like a hand-rolled version of Iterator::find:
https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.find

? NodeWalk implements Iterator, so it may be useful to pull the bulk of logic here out into a predicate function. Dunno.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Hmm... I can pull out the per-node logic and into a probe_node predicate. The catch with find itself is that each step is fallible and needs ? to propagate. try_find would make a good fit but I believe it's not stable. So I could do something like:

devinfo
    .walk_node()
    .map(|node| probe_node(log, &node.map_err(SwitchDetectError::DevInfo)?))
    .find_map(Result::transpose)
    .transpose()

but that feels harder to read than a loop. Not to mention doing a double transpose just to make it work which feels icky. Let me know which you think is clearer.

Comment thread sled-hardware/src/softnpu.rs Outdated
@sion42x

sion42x commented Sep 5, 2026

Copy link
Copy Markdown
Contributor Author

Tests post c6b42fc on Madrid:

[madrid]root@oxz_switch0:~# pilot host exec -c 'grep -h -E "found tofino asic|found SoftNPU 9p device|probe failed|skipping pumpkind" /var/svc/log/oxide-sled-agent:default.log /pool/ext/*/crypt/debug/global/oxide-sled-agent* 2>/dev/null | cut -c1-150' 14-17
14  BRM42220081        ok: {"msg":"found tofino asic","v":0,"name":"SledAgent","level":30,"time":"1986-12-28T00:00:44.501031762Z","hostname":"BRM42220081","pid":673,"component":
15  BRM42220046        ok: 
16  BRM42220007        ok: {"msg":"found tofino asic","v":0,"name":"SledAgent","level":30,"time":"1986-12-28T00:00:43.850669382Z","hostname":"BRM42220007","pid":674,"component":
17  BRM42220004        ok: 

On voxel:

root@helios1:~# for i in g0 g1 g2; do
> voxel host exec -c 'grep -h -E "found tofino asic|found SoftNPU 9p device|probe failed|skipping pumpkind" /var/svc/log/oxide-sled-agent:default.log /pool/ext/*/crypt/debug/global/oxide-sled-agent* 2>/dev/null | cut -c1-150' $i
> done
Sep 05 10:26:40.842 INFO set propolis binary to /root/propolis-9pexp/target/release/propolis-server
{"msg":"not an Oxide sled; skipping pumpkind","v":0,"name":"SledAgent","level":30,"time":"2026-09-04T17:35:22.830647805Z","hostname":"g0","pid":792,"c
{"msg":"found SoftNPU 9p device","v":0,"name":"SledAgent","level":30,"time":"2026-09-04T17:35:23.647422767Z","hostname":"g0","pid":792,"component":"Bo
Sep 05 10:26:59.634 INFO set propolis binary to /root/propolis-9pexp/target/release/propolis-server
{"msg":"not an Oxide sled; skipping pumpkind","v":0,"name":"SledAgent","level":30,"time":"2026-09-04T17:35:08.525600963Z","hostname":"g1","pid":741,"c
Sep 05 10:27:14.049 INFO set propolis binary to /root/propolis-9pexp/target/release/propolis-server
{"msg":"not an Oxide sled; skipping pumpkind","v":0,"name":"SledAgent","level":30,"time":"2026-09-04T17:36:12.543212179Z","hostname":"g2","pid":851,"c
{"msg":"found SoftNPU 9p device","v":0,"name":"SledAgent","level":30,"time":"2026-09-04T17:36:13.375344975Z","hostname":"g2","pid":851,"component":"Bo

Working as expected on all scrimlet/non-scrimlet + rack/voxel combinations.

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