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
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
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]
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"]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]
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.
- "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
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
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 loops5Choosing 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.
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]
Fill the blanks for a customer with a two-tier tree where the storage nodes hang off two of the spine switches instead of the leaves.
- ftree is ____ here, because the rule “____” is violated.[1]
- The engine to propose is ____, and the file that must accompany it is
-a/____.[2] - To let the storage nodes traverse a switch the wrong way around, the two options are
-G/____and-H/____, and the warning attached to them is ____.[1][2] - If the customer also asks for SHARP, the answer is ____, because SHARP’s engine list is ____.[9]
- To prove which engine ran, you would read ____ and then ____.[6][8]
A Dell customer is quoting a 2-tier NDR fabric for 96 nodes. Their draft config is one line: -R ftree. They also want SHARP, they intend to run the SM on a managed spine switch to save a server, and they have set lmc 2 because “more paths is better”.
Produce a one-page review that (a) names every documented rule their design violates, each with the rule quoted, (b) gives the configuration you would ship instead, including the GUID files and whether you would set no_fallback, (c) states what has to change before SHARP can work at all, and (d) lists the exact commands you would run after the change window to prove the fabric is routed the way you claimed.
Acceptance criteria: at least three violations named with their source rule; a decision on no_fallback with a reason tied to how the customer will notice a failure; SM placement addressed explicitly; and every verification step producing a file or a string you can paste into a ticket.
What goes back to the network lead
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
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.
- If
sminfoalready 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] - 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 UPin/var/log/opensm.log, andibstatmoving 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. ibroute <lid>for the far end’s LID, thendump_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.- Mutating step. Restart the SM with the unicast cache:
sudo kill $(cat /var/run/opensm-lab.pid)thensudo opensm -R minhop -A -F /tmp/opensm-lab.conf -B -J /var/run/opensm-lab.pid. Expected:SUBNET UPagain.[2] Rollback: same kill command; drop-Ato return to the previous behaviour. - Reboot or reload the second host, then read
/var/log/opensm.logacross 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 emptydiff-dump_lftsbefore 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. sudo kill $(cat /var/run/opensm-lab.pid)and confirm withsminfothat no SM remains. Compareibstatagainst your pre-flight file. Expected: identical device, port and rate lines.- Optional, only in a customer lab with at least two switches and written permission:
ibdiagnet -rand readibdiagnet2.fdbsplusopensm-ftree-ca-order.dumpfor a real fat tree. Expected strings:-I- no credit loops foundfrom the routing validation.[6][7] Rememberibdiagnet2.fdbsis 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]
Goal: choose engines from drawings, then exercise the configuration surface of OpenSM without touching a fabric.
- Draw or print four fabrics: a pure two-tier fat tree; the same tree with 60 percent of one scalable unit populated; a 3D torus; an arbitrary mesh with one faulty link. For each, write down the engine, the GUID files it needs, and what OpenSM does if that engine fails. Expected: your four answers match the Worked example above. If not, re-read the rank and port-group rules before continuing.[1]
opensm -c /tmp/opensm-lab.conf- expected: OpenSM dumps a full configuration template and exits.[2] If the binary is missing, installopensmfrom your distribution; it is a separate upstream repository fromrdma-core, so a host can haveinfiniband-diagsand still have no subnet manager.grep -nE 'routing_engine|no_fallback|lmc|ucast_cache|scatter_ports|port_shifting' /tmp/opensm-lab.conf- expected: the shipped defaults, includinglmc 0and a disabled scatter-ports value. Record each one next to the UFM value from the notes (routing_engine = ar_updn,scatter_ports = 8,use_ucast_cache = TRUE) and keep the pair, never a single number.[2][3]- Edit the file so it reads
routing_engine ftree,updn,no_fallback, then write out, in one sentence each, the two failure texts you expect: what appears if the tree does not qualify for ftree, and what the subnet looks like if Up/Down also fails with the fallback suppressed.[1] - Build the root and compute-node GUID files by hand from your drawing: one GUID per line, roots in
root_guids.confand compute nodes incn_guids.conf. Expected: you can state which engine reads which file without looking it up.[2] - Open the FabricTopologyExplorer above, select the routing overlay, and step through fat-tree, rail-optimized and SLG. For each, write which engines the panel says are legal and why the SLG shape disqualifies the switch-embedded SM.[5]
- Optional containerlab rehearsal: build the same wiring map in
~/containerlabwith Linux or FRR nodes to practise the inventory and cabling diff. State explicitly in your notes that containerlab carries Ethernet, not InfiniBand, so nothing about IB routing engines is being tested - only your wiring map.
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.
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.
- Current OpenSM Routing (routing-engine reference) · fetched 2026-09-07
- opensm(8) man page source, linux-rdma/opensm master · fetched 2026-09-07
- UFM Enterprise 6.24.1 User Manual: UFM Subnet Manager Default Properties · fetched 2026-09-07
- UFM Enterprise Appliance Software 1.6.0: InfiniBand Commands · fetched 2026-09-07
- Subnet Manager | NVIDIA MLNX-OS User Manual v3.12.6200 LTS · fetched 2026-09-07
- Routing Validation | IBUtils2 2.26.0 · fetched 2026-09-07
- ibdiagnet Dump Files | IBUtils2 · fetched 2026-09-07
- ibroute(8) man page · fetched 2026-09-07
- NVIDIA SHARP 3.8.0: Setting up NVIDIA SHARP Environment · fetched 2026-09-07
- 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.
- LIDs, GIDs, GUIDs and LMCElsewhere in this course · Same ground: LMC, opensm and routing
- QoS: service levels, virtual lanes, SL2VL and VL arbitrationElsewhere in this course · Same ground: opensm, ufm and defaults
- Adaptive routing: per-packet spraying and its eligibility rulesSpectrum-X course · Same ground: definition, routing and rules