Skip to content

Routing engines and how OpenSM picks a path

S3·E1SUBNET UP, and the tree is not a tree · Dell customer lab, Round Rock, three days before PoC sign-off

S3·E1Analyze~30 minsources checked todaylab mutates hardwareverified against OpenSM master current-routing.txt + opensm(8); UFM Enterprise 6.24.1 SM default properties; UFM Appliance 1.6.0 CLI; MLNX-OS 3.12.6200 LTS; IBUtils2 2.26.0. Research notes fetched 2026-09-07

Builds on: Bringing up OpenSM, QoS: service levels, virtual lanes, SL2VL and VL arbitration

Before you read: what do you already know?

3 quick questions. Wrong answers are fine and expected; trying first makes the lesson stick.

After this lesson you can

  • Select a routing engine for a given fabric shape and justify the choice from that engine's own documented requirements.
  • Predict what OpenSM does when the chosen engine fails, with and without `no_fallback` in the `-R` list.
  • Name the GUID files each engine consumes (`-a`, `-u`, `-G`) and state what each one changes.
  • Explain why fat-tree routing refuses LMC greater than 0 and where Up/Down forbids running the SM.
  • Read the resulting forwarding state back from a fabric with `ibroute`, `dump_lfts` and `ibdiagnet -r`.

Episode 1 — SUBNET UP, and the tree is not a tree

The situation · Dell customer lab, Round Rock, three days before PoC sign-off

Three days before sign-off, and the 96-node NDR tree in the Round Rock lab passes every check anyone in the room knows how to run. ibstat reads Active on every host. The OpenSM log says SUBNET UP. Only the all-to-all phase of the customer’s imaging benchmark is a third slower than the pod they own, and the network lead has written “cables” in the notebook twice and underlined it once. The Dell SE is holding a coffee that went cold an hour ago: Friday’s sign-off releases the order for two scalable units, and row 41 of the promise spreadsheet says “fabric parity”.

You ask a smaller question: which engine actually ran? Their configuration line is -R ftree. Their drawing has the storage nodes hanging off two spine switches, and fat-tree routing requires that all the CAs are at the same tree level.[1] So ftree declined, and OpenSM did what it always does: if all configured routing engines fail, it will always attempt to route with Min Hop unless no_fallback is included in the list.[1]

That fallback exists because a subnet with no forwarding tables is useless, and MinHop always works - a min-hop matrix, then LFT output ports assigned with per-port LID counters, optimising nothing about anybody’s traffic pattern.[1] Safety by default, silence as the price.

SUBNET UP proves the subnet was routed. It never proves it was routed the way you asked.

The SE wants to know what to change in the file, which is the wrong first move. Start with how OpenSM reads that list.

1The -R list is a fallback chain, not a preference

OpenSM offers ten routing engines: minhop, updn, dnup, ftree, lash, dor, torus-2QoS, dfsssp, sssp and nue, and the man page’s supported list also includes file.[1][2] You select them with -R, and the important sentence is about ordering: multiple routing engines can be specified separated by commas so that a specific ordering of routing algorithms will be tried if earlier routing engines fail, and if all configured routing engines fail, OpenSM will always attempt to route with Min Hop unless no_fallback is included in the list.[1] MinHop is also what you get when no engine is given at all.[1]

That single sentence explains most “why is this fabric slow” tickets on a tree. A customer configures ftree, the tree does not qualify, OpenSM falls through to MinHop, the log still says SUBNET UP, every ibstat reads Active, and the fabric behaves like an unbalanced mesh under a shift pattern. Nothing is broken; the engine you asked for simply did not run.[1]

NVIDIA layers its own engine names on top through UFM. The appliance CLI lists them verbatim as ar-dor, ar-ftree, ar-torus, ar-updn, chain, dfp, dfp2, dor, file, ftree, minhop, pqft, torus-2QoS, updn, set with a command such as ib sm routing-engines ar-updn.[4] UFM’s shipped SM default is routing_engine = ar_updn, which is the opposite of the upstream feel of the tool.[3] So “what is the default engine” has two correct answers and you must ask who runs the SM before giving either.[2][3]

Rendering diagram…
Diagram source (Mermaid)
flowchart TD; S(["Customer fabric"]) --> Q1{"Is the shape a tree?"}; Q1 -->|"pure fat tree, all CAs at one rank"| F["ftree or NVIDIA ar_ftree - feed -a root_guid_file and -u cn_guid_file"]; Q1 -->|"tree-like but irregular or partly cabled"| U["updn or ar_updn - give -a root_guid_file, do not trust the statistical root autodetect"]; Q1 -->|"mesh or hypercube, cabled as such"| D["dor - deadlock free on meshes and hypercubes"]; Q1 -->|"2D or 3D torus"| T["torus-2QoS with --torus_config - routes around failures, keeps SL values"]; Q1 -->|"arbitrary or faulty, no regular shape"| N["nue - deadlock free on any topology, --nue_max_num_vls default 1"]; Q1 -->|"DragonFly plus"| DF["dfp or dfp2 - UFM engine set only, not upstream OpenSM"]; F --> C{"Add no_fallback?"}; U --> C; D --> C; T --> C; N --> C; DF --> C; C -->|"yes"| C1["Engine failure is loud: no MinHop safety net"]; C -->|"no"| C2["Engine failure is silent: MinHop routes the fabric and SUBNET UP still appears"]
Work the shape first, the engine second, and decide no_fallback last. The right-hand branch is the choice most customers never make on purpose.

2What each tree engine demands of the cabling

MinHop is the baseline: a two-stage algorithm that builds a min-hop matrix and then assigns LFT output ports with per-port LID counters for balancing.[1] It always works and it optimises nothing about your traffic pattern.

Up/Down is the engine for trees that are not pure. The reference says it should be used if the subnet is not a pure fat tree and one of its loops may experience a deadlock.[1] Two properties matter in the field. First, root detection is statistical: since the algorithm is statistical, it may not find any root nodes, and if that stage cannot find any root nodes and the user did not specify a GUID list file, OpenSM defaults back to the Min Hop routing algorithm.[1] Give it -a/--root_guid_file rather than hoping.[2] Second, Up/Down routing does not allow LID-routed communication between switches located inside spine switch systems, so you cannot run the SM on switches other than the leaf switches of the fabric.[1] On a customer design with a chassis spine, that sentence disqualifies an SM placement before you have drawn a single cable.

The fat-tree engine optimises for the shift communication pattern, handles non-constant K, cases where not all leaves are present, and any Constant Bisectional Ratio, and like Up/Down it prevents credit-loop deadlocks.[1] Its rules with no root GUID file are exact: tree rank between two and eight inclusively; same-rank switches must have identical numbers of up-going and down-going port groups and identical port counts per group, where a port group is ports that are connected to the same remote switch; and all the CAs have to be at the same tree level.[1] Supply a root GUID file and the topology need not be a pure fat tree - only rank 2 to 8 and all compute nodes at the same rank still hold.[1] One more rule catches designers: LMC greater than 0 is not supported by fat-tree routing, and if it is specified the default routing algorithm is invoked instead.[1]

Three GUID files shape the result: -a/--root_guid_file for roots, -u/--cn_guid_file for compute nodes, and -G/--io_guid_file with -H/--max_reverse_hops for I/O nodes that may traverse a switch the wrong way around a bounded number of times.[2] The last one carries its own warning: it should never be used to connect nodes with high bandwidth traffic between them, because routes the other way around can in theory cause credit loops.[1] ftree also writes opensm-ftree-ca-order.dump next to the OpenSM log, giving the compute-node order that matches the routing tables.[1]

baseline shape — every inter-node flow crosses the spine
Fat tree (node-aligned) — one slice: 3 nodes × 4 rails, 4 leaf, 2 spineS0spine (root)rootS1spine (root)rootL0leaf — node n0CN rankL1leaf — node n1CN rankL2leaf — node n2CN rankL3leaf — no node in this sliceCN ranknode n0 — 4 of 8 rails shownr0CAr1CAr2CAr3CAnode n1 — 4 of 8 rails shownr0CAr1CAr2CAr3CAnode n2 — 4 of 8 rails shownr0CAr1CAr2CAr3CA
1 SU
Path

Click one HCA for the source, another for the destination. Hops are counted as switch ASICs traversed — a link count is hops + 1.

Fat tree (node-aligned)

  • Leaf switches under spine (root) switches. Here every rail of a node drops on that node's own leaf, so nothing is rail-aligned: all inter-node traffic is leaf → spine → leaf, 3 switch hops.
  • Quantum-2 switches "enable a variety of topologies, including Fat Tree, SlimFly, DragonFly+, multi-dimensional Torus, and more"; the QM9700 family is positioned for "small to medium-sized deployments" on a two-level fat tree.
  • Ceiling: a two-level fat tree on Quantum-X800 Q3400 supports "up to 10,368 network interface cards (NICs)".

FAE angle. The empty leaf is deliberate. For a partly populated SU the RA says to buy the full leaf count and leaf-spine cables anyway and leave the positions empty — it "will ensure optimal traffic routing". Shrink the fabric instead and the tree turns asymmetric, ftree's rank rules stop holding, and job-to-job timing goes non-deterministic.

QM97XX User Manual — Introduction

Which engine OpenSM should run on this shape
  • "OpenSM offers ten routing engines": minhop, updn, dnup, ftree, lash, dor, torus-2QoS, dfsssp, sssp, nue — plus file. -R takes an ordered comma list, and MinHop is always the last resort "unless 'no_fallback' is included in the list".
  • NVIDIA adds its own set through UFM: ar-dor, ar-ftree, ar-torus, ar-updn, chain, dfp, dfp2, dor, file, ftree, minhop, pqft, torus-2QoS, updn. UFM's default is routing_engine = ar_updn.
  • Up/Down auto-detects roots statistically and "may not find any root nodes" — then it falls back to MinHop. Give it -a/--root_guid_file instead of hoping. It also bans SM placement: "you cannot run SM on switches other than the leaf switches of the fabric."
  • Routes are sticky: "OpenSM will preserve existing routing in any case where there is no change in the fabric switches unless the -r (--reassign_lids) option is specified."
  • On this shape: ftree (or NVIDIA's ar_ftree) when the tree is pure; MinHop is the implicit fallback unless no_fallback is in the -R list.
  • On this shape: Pure-fat-tree rules with no root-GUID file: rank 2–8, equal up/down port-group counts per rank, and "All the CAs have to be at the same tree level (rank)."
opensm -R ftree,updn,no_fallback -a /etc/opensm/root_guids -u /etc/opensm/cn_guids
ibroute <lid>        # this switch's linear forwarding table
dump_lfts            # every switch's LFT

OpenSM current-routing.txt

Scalable-unit arithmetic — 1 SU

DGX H200 SuperPOD compute fabric — QM9700 NDR

Sources: opensm(8) · UFM SM defaults · MLNX-OS Subnet Manager · SHARP environment · Quantum-X800 switches · MCA4J80 ACC · ibdiagnet · ibdiagnet dump files · Dell XE9680 technical guide

Routing overlay on the plain fat tree. Switch topology to rail-optimized and then to SLG and re-read the engine panel: the shape changes which engines are legal, not just which are fastest.

3The deadlock-freedom family

Four engines exist because deadlock, not bandwidth, is the hard constraint on an irregular fabric.

LASH is Layered Shortest Path Routing: it groups shortest paths into SLs, or layers, so that no layer contains a cycle, opening a new layer when a path would deadlock and then rebalancing.[1] It has a behaviour that surprises people debugging one direction of a flow: LASH ensures the same SL is used for all source and destination pairs in both directions, and there is no guarantee that the return path for a given destination-source pair will be the reverse of the route source-destination.[1] Activate it with -R lash -Q; --do_mesh_analysis preconditions switch-port assignments in regular cartesian meshes, which may reduce the number of SLs required, and --lash_start_vl defaults to 0.[2] LMC greater than 0 is not supported by LASH routing.[2]

DOR avoids port equalisation except for redundant links between the same two switches, which is what makes it deadlock-free on hypercubes and meshes when they are actually cabled as such.[1] Torus-2QoS is DOR-based for 2D and 3D torus, supports two QoS levels, and can route around multiple failed fabric links or a single failed fabric switch without introducing deadlocks and without changing path SL values granted before the failure; its config file comes from --torus_config.[1][2] Nue is the general answer: 100 percent applicable and deadlock-free for any arbitrary or faulty network topology and any number of virtual lanes, including the absence of VLs.[1] Its --nue_max_num_vls defaults to 1 to enforce deadlock-freedom even if QoS is not enabled, with 0 meaning auto-detect the fabric maximum; a higher value results in better path balancing.[2]

The file engine is the odd one out. It just loads the LFTs from the file specified, with no reaction to real topology, and multicast is not affected by the file routing engine because that still uses min-hop tables.[1] Treat it as a forensic and reproduction tool, not a production engine.

One consequence to carry into the rest of the module: SHARP does not accept any engine you like. Its documented requirement is tree-based topologies with updn, ar_updn, ftree or ar_ftree; DragonFly+ with dfp; and hypercube topologies with the dor routing engine with dor_hyper_cube_mode enabled.[9] Choosing lash or nue for deadlock reasons therefore takes SHARP off the table, and that trade belongs in the design conversation, not in a later escalation.[9]

4After the engine: stickiness, cache and balance

Routing is not recomputed as often as customers assume. OpenSM will preserve existing routing in any case where there is no change in the fabric switches unless -r/--reassign_lids is specified, and if a link is added or removed, OpenSM does not recalculate the routes that do not have to change.[1] -A/--ucast_cache goes one step further: it prevents routing recalculation, which is a heavy task in a large cluster, when there was no topology change detected during the heavy sweep, and the man page names host reboot as the common case it covers, which would otherwise force two full recalculations.[2] UFM ships use_ucast_cache = TRUE.[3]

Two knobs exist purely to break unlucky symmetry. --port-shifting counteracts the case where, in some fabrics and particularly cluster environments, routes commonly align and congest with other routes due to algorithmically unchanging traffic patterns.[2] --scatter-ports randomises port selection instead of round-robin, and if the value is 0, which is the default, the scatter ports option is disabled; MLNX-OS adds that it is recommended to use a prime number for the seed.[2][5] UFM does not ship the upstream default here either: its table shows scatter_ports = 8.[3] -X/--guid_routing_order_file fixes the order in which port GUIDs are routed for MinHop and Up/Down, which is how storage or service nodes get first pick of link balancing.[2][5]

Then prove it. ibroute dumps a switch’s unicast forwarding table, with a default range of all valid entries from 1 to FDBTop, -a to show invalid entries and -M to switch to multicast.[8] dump_lfts does the same for every switch.[2] Fabric-wide, ibdiagnet -r provides a report of the fabric qualities and validates unicast routing, static and adaptive, plus multicast, and its credit-loop success string is -I- no credit loops found.[6] The evidence files are ibdiagnet2.fdbs for unicast FDBs and ibdiagnet2.mcfdbs for multicast, and note that ibdiagnet2.fdbs is one of the files disabled by default, so it needs --enable_output.[7]

opensm -R ftree,updn,no_fallback \
  -a /etc/opensm/root_guids.conf \
  -u /etc/opensm/cn_guids.conf \
  -A -F /etc/opensm/opensm.conf
ibroute 3                 # one switch LFT, by LID
dump_lfts                 # every switch LFT
ibdiagnet -r              # routing validation, credit loops

5Choosing on a customer call

The analysis skill here is turning a cabling drawing into an engine plus its inputs plus its failure mode, in that order.

Four drawings, four decisions

1. Pure two-tier fat tree, 8 leaves and 4 spines, every node with the same rail count, all hosts on leaves. Engine: ftree (or NVIDIA ar_ftree under UFM).[1][4] Inputs: -a/--root_guid_file naming the four spines and -u/--cn_guid_file naming the compute nodes.[2] Check first: rank is 2, which is inside the required 2 to 8; all CAs are at the same rank; each leaf presents the same up-going port-group count.[1] Failure mode without no_fallback: silent MinHop.[1] Also confirm LMC is 0, because fat-tree routing does not support LMC greater than 0.[1]

2. Same tree, but only 60 percent of the scalable unit is populated and two leaves are half cabled. Engine: updn or ar_updn with an explicit -a root list, because the port-group equality rule no longer holds and ftree will decline.[1][3] Failure mode: Up/Down’s statistical root autodetect may find nothing and fall back to MinHop, which is exactly why the root GUID file is not optional here.[1]

3. A 3D torus. Engine: torus-2QoS with --torus_config.[1][2] Why not DOR alone: torus-2QoS is the one that can route around multiple failed links or a single failed switch without introducing deadlocks and without changing path SL values granted before the failure.[1] Trade to declare: SHARP’s routing-engine list does not include it.[9]

4. An arbitrary lab mesh with a known-bad link. Engine: nue.[1] Input: leave --nue_max_num_vls at 1 unless you have confirmed the VL count, since the default exists to enforce deadlock-freedom even if QoS is not enabled.[2] Failure mode: none documented for topology shape - that is the point of the engine.

For all four, the verification sequence is identical: OpenSM log for the engine that ran, ibdiagnet -r for routing validation and -I- no credit loops found, then ibroute on one switch to read a real LFT.[6][8]

What goes back to the network lead

How it ended

You hand over evidence, not an opinion: the OpenSM log naming the engine that ran, ibdiagnet -r with its -I- no credit loops found string, and a forwarding table read back with ibroute.[6][8] “Show me the counter,” the network lead says; for once there is one. The shipped configuration becomes updn with an explicit -a root GUID file, LMC back to 0 because fat-tree routing does not support LMC greater than 0, and no_fallback so the next failure is loud.[1][2]

What you say: it was never the cables. The engine you asked for declined, MinHop routed the fat tree, and the log said SUBNET UP throughout.

Sign-off holds. Then the notebook opens again: their production pod, right engine, overnight job still slow. The night-shift operator is already awake.

Lab

Mutating steps ahead. Needs a maintenance window, out-of-band access (BMC/iDRAC/rshim console) and a rollback path. Record the pre-flight inventory before changing anything. Never on a production host.

Goal: run a real subnet manager on the Dell-lab card, read the forwarding state it programs, and prove the unicast cache changed nothing after a reboot.

Pre-flight inventory (read-only). ibstat for device name, port state and base LID; ibstatus for the rate string; sminfo to see whether an SM is already running; ibnetdiscover -l for the node list. Save all four to files with today’s date - they are your rollback reference and your before-picture.

  1. If sminfo already reports a master SM on this subnet, stop here and use that fabric read-only. Two subnet managers on one subnet is a change you do not make in someone else’s lab.[5]
  2. Mutating step. Start a subnet manager on a two-node back-to-back link: sudo opensm -R minhop -F /tmp/opensm-lab.conf -B -J /var/run/opensm-lab.pid. Expected: SUBNET UP in /var/log/opensm.log, and ibstat moving the port from Initializing to Active.[2] Rollback: sudo kill $(cat /var/run/opensm-lab.pid); the ports stay Active until the next reset and no persistent configuration was written.
  3. ibroute <lid> for the far end’s LID, then dump_lfts > /tmp/lfts-before.txt. Expected: a linear forwarding table listing valid entries from 1 to FDBTop.[8] On a back-to-back pair with no switch there is no LFT to read - record that fact rather than inventing output; it is the honest limit of this lab.
  4. Mutating step. Restart the SM with the unicast cache: sudo kill $(cat /var/run/opensm-lab.pid) then sudo opensm -R minhop -A -F /tmp/opensm-lab.conf -B -J /var/run/opensm-lab.pid. Expected: SUBNET UP again.[2] Rollback: same kill command; drop -A to return to the previous behaviour.
  5. Reboot or reload the second host, then read /var/log/opensm.log across the event and record the sweep entries and their timestamps. Expected with -A: the log shows the sweep without a unicast route recalculation, because the cache prevents recalculation when no topology change was detected.[2] There is still no LFT to diff on a switchless pair, so record that limit rather than an empty diff - dump_lfts before and after is the check you would run on a real fabric with a switch in it. Rollback: none needed; the reboot is on the peer host and restores itself, and the SM is stopped in step 6.
  6. sudo kill $(cat /var/run/opensm-lab.pid) and confirm with sminfo that no SM remains. Compare ibstat against your pre-flight file. Expected: identical device, port and rate lines.
  7. Optional, only in a customer lab with at least two switches and written permission: ibdiagnet -r and read ibdiagnet2.fdbs plus opensm-ftree-ca-order.dump for a real fat tree. Expected strings: -I- no credit loops found from the routing validation.[6][7] Remember ibdiagnet2.fdbs is disabled by default and needs --enable_output, and check the tool’s own tail line for the output directory rather than assuming one - the NVIDIA pages disagree on the default path.[7]

Retrieval check

10 questions from memory. Answer before looking anything up; misses become flashcards.

Explain it to a Dell SE

Explain to a Dell SE, in five sentences, what `-R ftree,updn,no_fallback` means, what OpenSM will do if the customer's tree is only half cabled, and how you would prove which engine actually ran.

14 flashcards for this lesson — 0 in deck. Spaced review lives at /review.

Sources

Facts in this lesson were checked against OpenSM master current-routing.txt + opensm(8); UFM Enterprise 6.24.1 SM default properties; UFM Appliance 1.6.0 CLI; MLNX-OS 3.12.6200 LTS; IBUtils2 2.26.0. Research notes fetched 2026-09-07. Dates are when each page was fetched.

  1. Current OpenSM Routing (routing-engine reference) · fetched 2026-09-07
  2. opensm(8) man page source, linux-rdma/opensm master · fetched 2026-09-07
  3. UFM Enterprise 6.24.1 User Manual: UFM Subnet Manager Default Properties · fetched 2026-09-07
  4. UFM Enterprise Appliance Software 1.6.0: InfiniBand Commands · fetched 2026-09-07
  5. Subnet Manager | NVIDIA MLNX-OS User Manual v3.12.6200 LTS · fetched 2026-09-07
  6. Routing Validation | IBUtils2 2.26.0 · fetched 2026-09-07
  7. ibdiagnet Dump Files | IBUtils2 · fetched 2026-09-07
  8. ibroute(8) man page · fetched 2026-09-07
  9. NVIDIA SHARP 3.8.0: Setting up NVIDIA SHARP Environment · fetched 2026-09-07
  10. NVIDIA-Certified Professional: AI Networking (NCP-AIN) certification page · fetched 2026-09-07

The same idea elsewhere

Other lessons that cover this ground, sometimes from another course's angle.