Skip to content

LIDs, GIDs, GUIDs and LMC

S1·E2The node that vanished at 03:12 · Customer data center, night shift, eleven days into the PoC

S1·E2Understand~25 minsources checked todaylab mutates hardwareverified against RFC 4392, opensm(8) and rdma-core man pages (master), OpenSM current-routing.txt, UFM Enterprise 6.24.1 SM defaults, Linux kernel sysfs-class-infiniband ABI - fetched 2026-09-07

Builds on: Who's who in an InfiniBand subnet

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

  • Distinguish LID, GID and GUID by size, lifetime and who assigns each one.
  • Explain why the GUID is the only persistent port identifier and why it can never appear as a packet address.
  • Predict the effect of LMC on the number of LIDs per port and state the routing engine that refuses LMC > 0.
  • Decide whether a fabric script should key on a LID or a GUID and justify the choice from the documented lifetime rules.

Episode 2 — The node that vanished at 03:12

The situation · Customer data center, night shift, eleven days into the PoC

Eight nodes were rebooted for a firmware update inside the maintenance window, and the monitoring says one never came back on the fabric. It is 03:12, the night-shift operator has the rack door open and an adapter half out of its bag, and because he labels everything, a strip of tape on the chassis already reads SUSPECT HCA. Those two words are in the ticket too. Acceptance is in nineteen days and a dead adapter is the last story anybody wants.

You join from home and ask for one thing before anybody unseats a card: the ibnetdiscover capture from right now, and the one taken before the window.

The GUID is in both captures. The LID is not the same in both.

That is the entire outage, and the reason an InfiniBand port carries more than one identifier. A LID is a 16-bit value assigned when the port becomes active, and a LID is always needed in a packet since the destination within a subnet is determined by it.[1] But the subnet manager only “may attempt to keep the LID values constant across reboots, but that is not a requirement”.[1] The name that survives a reboot is the GUID, maintained by hardware, which helps restrict impersonation or spoofing[3] and is the only persistent identifier of a port — though it can never be used as an address in a packet.[1]

Their availability check is pinned to the identifier the fabric is allowed to change.

Start with what each one is and how long it lives.

1Three identifiers, three lifetimes

RFC 4392 gives all three definitions in a few lines, and they are worth quoting exactly because everything else follows from them. “A port, in a data packet, is identified by a Local Identifier (LID) and optionally a Global Identifier (GID).”[1] “The LID is a 16-bit value that is assigned when the port becomes active.”[1] “The GID is 128 bits long and is formed by the concatenation of a 64-bit IB subnet prefix and a 64-bit EUI-64-compliant portion. The EUI-64 portion of a GID is referred to as the Global Unique Identifier (GUID)”.[1]

Then the sentence that decides how you write scripts for the next ten years: “The GUID is the only persistent identifier of a port. However, it cannot be used as an address in a packet.”[1] And its companion: “The subnet manager may attempt to keep the LID values constant across reboots, but that is not a requirement.”[1]

When each one is on the wire is also specified: “The GID in the packet is needed only when communicating across an IB subnet, though it may always be included… A LID is always needed in a packet since the destination within a subnet is determined by it.”[1] So inside one subnet - which is every fabric in this module - the LID is doing the steering, and the GID is optional context.

NVIDIA restates the GUID as a security property rather than an addressing one: “Each node and port are identified through a 64-bit Global Unique Identifier (GUID) maintained by hardware, which helps restrict impersonation or spoofing.”[3] That is the reason every fabric-configuration file keys on GUIDs - root-GUID files, compute-node GUID files and partitions.conf port lists all take GUIDs, never LIDs.[8][2]

One honest gap: you will see LID range tables in the wild - unicast up to 0xBFFF, multicast above 0xC000, 0xFFFF permissive. No primary page fetched for this course states those boundaries; RFC 4392 says only that the LID is a 16-bit value.[1] Treat the ranges as folklore until you can cite the IBA specification itself, and never put them in a customer answer as if NVIDIA published them.

2The GID in detail: prefix, scope and multicast

The subnet prefix is a knob, not a constant. OpenSM’s default is 0xfe80000000000000, settable with --subnet_prefix; UFM ships the same value as subnet_prefix = 0xfe80000000000000, marked read-write.[2][5] Because that is the link-local prefix, a bare GID read off two different fabrics looks identical up to the GUID - which is a mild trap when you are comparing captures from two customer sites.[2]

Unicast GID scopes mirror IPv6: link-local FE80/10, which is never forwarded past the IB subnet; site-local FEC0/10; and global.[1] Multicast GIDs have their own shape: FFxy:<112 bits>, where the x nibble is the flags field 000T - T=0 is a permanently assigned or well-known group and T=1 a transient one - and the y nibble is the scope, with 2 = link-local, 5 = site-local, 8 = organization-local and 0xE = global.[1] You will meet those numbers again in lesson 4, because IPoIB’s broadcast group is a multicast group with a scope and a rate.[8]

Reading identifiers on a live fabric splits into two routes. From the SMA, smpquery fetches attributes directly: Nodeinfo (NI), Nodedesc (ND), Portinfo (PI), GUIDInfo (GI) and more, addressed by LID (smpquery portinfo 3 1), by GUID with -G, or by direct route with -D.[6] From the local driver, the stable kernel sysfs ABI exposes ports/<port-num>/lid (“Port LID”), ports/<port-num>/lid_mask_count (“Port LID mask count”), ports/<port-num>/sm_lid (“Subnet manager LID for port’s subnet”), plus device-level node_guid and sys_image_guid.[7] The whole infiniband-diags suite shares the same addressing flags: -D for directed route, -G by GUID, -L by LID, -s for the SM LID.[9]

baseline shape — every inter-node flow crosses the spine
Fat tree (node-aligned) — one slice: 3 nodes × 4 rails, 4 leaf, 2 spineS0spine (root)port 0 LID onlyS1spine (root)port 0 LID onlyL0leaf — node n0port 0 LID onlyL1leaf — node n1port 0 LID onlyL2leaf — node n2port 0 LID onlyL3leaf — no node in this sliceport 0 LID onlynode n0 — 4 of 8 rails shownr0srcLID + GIDr1LID + GIDr2LID + GIDr3LID + GIDnode n1 — 4 of 8 rails shownr0LID + GIDr1LID + GIDr2LID + GIDr3LID + GIDnode n2 — 4 of 8 rails shownr0dstLID + GIDr1LID + GIDr2LID + GIDr3LID + GID
1 SU
Path

3 switch hops · 2 equal-cost paths · same rail (rail 0)

L0 → S0 → L2 | L0 → S1 → L2

This crosses the spine layer. Every equal-cost path listed is a candidate adaptive routing can pick between (ar_mode = 3).

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

Leaf selected
Leaf switch L0
  • A switch "moves IB packets from one port to another based on routing tables configured by the Subnet Manager".
  • All 4 rails of node n0.
  • Its external ports carry no LID — they "are transparent to other end nodes". Only switch port 0 is addressable, which is why ibnetdiscover shows a switch by GUID plus one port-0 LID.
  • Under ftree the leaves are the rank every compute node must share: "All the CAs have to be at the same tree level (rank)." Hang one node off a spine and the engine stops qualifying the tree.
ibnetdiscover -p          # every port: LID, portnum, GUID, width, speed, NodeDescription
iblinkinfo                # link state and rate per switch port
ibroute <lid>             # this switch's forwarding table

RFC 4392 §1.2 (switch port addressing)

LIDs, GIDs, GUIDs on this picture
  • Every HCA port gets a LID: "a 16-bit value that is assigned when the port becomes active", and "the subnet manager may attempt to keep the LID values constant across reboots, but that is not a requirement."
  • The GID is 128 bits — a 64-bit IB subnet prefix plus a 64-bit EUI-64 GUID. OpenSM and UFM both default the prefix to 0xfe80000000000000 (--subnet_prefix).
  • "The GUID is the only persistent identifier of a port. However, it cannot be used as an address in a packet."
  • Switch external ports — every leaf-spine and node-leaf port drawn here — carry no LID: they "are transparent to other end nodes". Only switch port 0, the management port, has one.
  • LMC is 0 by default: one LID, one path per port. -l/--lmc gives 2^LMC LIDs, range 0–7, and "should only be used if the subnet topology actually provides multiple paths between ports". Fat-tree routing does not support LMC > 0 — set it and OpenSM invokes the default engine instead.
  • FAE angle: never key a script, a partitions file or a root-GUID file on a LID. LIDs move at the next activation; GUIDs are burned in.
ibstat                       # port state, base LID, port GUID, rate
ibaddr                       # GID of the local port
smpquery -G nodeinfo <guid>  # query by GUID, not by LID

RFC 4392 §1.2

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

Address overlay with a source and destination picked. Read which identifier each element carries and how many hops the path takes - then change the topology and watch which identifiers survive the change.

3LMC: more LIDs per port, and what it costs

LMC is the LID Mask Control value, and OpenSM’s man page defines it in one sentence: “This option specifies the subnet’s LMC value. The number of LIDs assigned to each port is 2^LMC. The LMC value must be in the range 0-7.”[2] Without -l the default is 0 - one LID per port, therefore one path between any two ports.[2] UFM ships the same default, lmc = 0, read-write.[5]

The point of LMC is to give the SM a way to express several distinct paths between the same pair of ports, because the path is chosen by destination LID. The man page adds the constraint that stops people using it as a magic performance knob: “LMC values > 0 should only be used if the subnet topology actually provides multiple paths between ports, i.e. multiple interconnects between switches.”[2] When LMC is greater than zero, MinHop adds tie-breaks - prefer a port going to a different systemImageGuid, then a different NodeGuid, then fall back to path count.[4]

Now the trap. “Note: LMC > 0 is not supported by fat-tree routing. If this is specified, the default routing algorithm is invoked instead.”[4] Nothing errors out. The customer set LMC to get multipathing, and quietly lost the routing engine they actually wanted. LASH does not support LMC > 0 either.[2] One more silent correction lives nearby: OpenSM’s own source clamps an out-of-range value back to the built-in default and logs it rather than refusing to start, so lmc 9 in a config file becomes lmc 0 with a log line most people never read - osm_subn_verify_config() reports “Invalid Cached Option Value:lmc = 9: Using Default:0” and carries on.[11]

Changing LID assignment at all is a maintenance-window action: -r / --reassign_lids forces reassignment, and “Specifying -r on a running subnet may disrupt subnet traffic. Without -r, OpenSM attempts to preserve existing LID assignments resolving multiple use of same LID.”[2] UFM ships reassign_lids = FALSE (disabled).[5]

4Field consequence: key on GUIDs, verify with both

Put the lifetimes side by side. The GUID is burned in and is what every configuration file references.[3][8] The LID is assigned at activation, only preserved on a best-effort basis, and can be forced to change by one flag.[1][2] Therefore: inventory, alerting and automation key on GUIDs; commands and forwarding key on LIDs.

A concrete workflow for a maintenance window: capture ibnetdiscover and iblinkinfo before and after, then diff by GUID and let the LID column be the thing that moves. iblinkinfo supports this directly with --diffcheck <keys> taking a comma-separated list from port, state, lid and nodedesc, and notes that “if port is specified alongside lid or nodedesc, remote port lids and node descriptions will also be compared”.[10] Its exit status is usable in a cron: “0 on success, -1 on failure to scan the fabric, 1 if check mode is used and inconsistencies are found”.[10]

Duplicate GUIDs deserve one paragraph of their own because they are the failure mode people misdiagnose as a bad card. “The SM has built-in logic that knows to detect duplicate GUIDs, and to isolate (not to configure) devices with duplicate GUIDs.”[3] By default OpenSM treats that as fatal and exits; -y / --stay_on_fatal keeps the SM alive when it “discovers duplicated guids or a 12x link with lane reversal badly configured”.[2] So the symptom of a cloned GUID is not a broken link - it is a node that never gets configured, or an SM that will not stay up.[3][2]

Episode 2 — 03:40, rack door closed

How it ended

You diff the two captures by GUID and let the LID column be the thing that moved — which is what iblinkinfo --diffcheck over lid and nodedesc exists for.[10] The node is present and Active, same GUID, new LID. The check broke, not the card. So you leave a rule instead of a fix: inventory and alerting key on GUIDs, because every root-GUID file and partitions.conf port list already does[8]; commands and forwarding key on LIDs. What you say to the operator: “Put the card back, and peel your label off.” At 06:00 the Dell SE forwards a photograph taken on somebody’s phone, with procurement copied in. The card in the picture says SDR.

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.

Mutating. Steps 1-4 are read-only and change nothing on the card. Steps 5-7 stop, restart and reconfigure a lab-only subnet manager - including a -r LID reassignment, which opensm(8) warns may disrupt subnet traffic on a running subnet - and each names its rollback. Lab fabric only, with no running jobs.

  1. Pre-flight inventory: ibstat, ibstat -p, ibv_devinfo | head -20. Record device name, port GUID, Base lid, LMC and SM lid before anything else.
  2. Read the same values from sysfs and confirm they agree: cat /sys/class/infiniband/mlx5_0/ports/1/{lid,lid_mask_count,sm_lid} and cat /sys/class/infiniband/mlx5_0/{node_guid,sys_image_guid}. Expected: the port LID matches ibstat’s Base lid and lid_mask_count matches its LMC. If a file is missing, the device is not an IB-mode port.
  3. Read the port’s GID: ibaddr for the GID in one line, and, if your driver exposes it, cat /sys/class/infiniband/mlx5_0/ports/1/gids/0. Expected: a 128-bit value whose first half is the subnet prefix (fe80… by default) and whose second half is the port GUID. Note that the stable kernel ABI page documents gid_attrs/… entries but not gids/<index>, so treat ibaddr as the authoritative read.
  4. Confirm the prefix claim by arithmetic, not by trust: split the GID you captured into two 64-bit halves and check that the low half equals the port GUID from step 1.
  5. Mutating only in the sense of restarting a lab SM - not the card. With opensm running on this host, note the LID, then kill $(cat /var/run/opensm.pid) and restart it without -r, and record the LID again. Expected: unchanged. Rollback: none needed - stopping and starting the SM restores the previous state, and if you started it by hand simply stop it again.
  6. Repeat step 5 with -r. Expected: LIDs may be reassigned. Do this only on a lab fabric with no running jobs, because the man page warns that -r on a running subnet may disrupt traffic. Rollback: restart opensm without -r and re-verify with ibstat.
  7. Optional, only where a real multi-path IB fabric exists: set -l 1 and re-read the LID range per port with ibstat and iblinkinfo. Expected: two LIDs per port. Rollback: restart the SM without -l.

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 four sentences, the difference between a LID, a GID and a GUID, and why the inventory spreadsheet they built after last quarter's maintenance window now points at the wrong servers.

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

Sources

Facts in this lesson were checked against RFC 4392, opensm(8) and rdma-core man pages (master), OpenSM current-routing.txt, UFM Enterprise 6.24.1 SM defaults, Linux kernel sysfs-class-infiniband ABI - fetched 2026-09-07. Dates are when each page was fetched.

  1. RFC 4392 - IP over InfiniBand (IPoIB) Architecture · fetched 2026-09-07
  2. opensm(8) man page source - linux-rdma/opensm master · fetched 2026-09-07
  3. NVIDIA InfiniBand Security Overview and Guidelines - Security in InfiniBand · fetched 2026-09-07
  4. Current OpenSM Routing (routing-engine reference) · fetched 2026-09-07
  5. UFM Enterprise 6.24.1 - UFM Subnet Manager Default Properties · fetched 2026-09-07
  6. smpquery(8) man page source - rdma-core master · fetched 2026-09-07
  7. Linux kernel ABI - sysfs-class-infiniband (stable) · fetched 2026-09-07
  8. OpenSM partitions.conf configuration reference · fetched 2026-09-07
  9. infiniband-diags(8) overview man page - rdma-core master · fetched 2026-09-07
  10. iblinkinfo(8) man page source - rdma-core master · fetched 2026-09-07
  11. OpenSM osm_subnet.c - compiled-in option defaults and osm_subn_verify_config() · fetched 2026-09-07

The same idea elsewhere

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