Resiliency and Congestion Management for AI Workloads Using the OCCL-NET Plugin
The OCI OCCL-NET plugin is designed to make large-scale AI training more reliable and efficient. It addresses network congestion and failures that can stall jobs, force restarts, and leave costly GPUs idle—particularly in OCI’s multi-planar GPU cluster architecture.
Built to work with NCCL and RCCL through their standard network-plugin interface, OCCL-NET provides cross-plane congestion management plus automatic failover and recovery for NIC and link failures. Because it operates independently of underlying switch and NIC vendors, OCI can avoid hardware lock-in while customers need no changes to their training applications or AI frameworks.
OCI will offer OCCL-NET free through Oracle HPC images and as open source. The plugin combines vendor-neutral deployment flexibility with improved resiliency and performance for customers running demanding AI workloads.
Using the OCCL-NET Plugin
The following instructions are for running a pre-built OCCL-NET network plugin, not for building the repository. The plugin leaves the application's NCCL installation in place and loads liboccl-net-occl-ib.so as the external NET plugin.
Before you Begin
Before using the plugin, the following configuration is required:
- Each participating host needs the same compatible plugin build, an NCCL runtime that supports the exported NET-plugin ABI, and access to the InfiniBand or RoCE devices selected for the job. The plugin exports ABI versions 6 through 12.
- Use an absolute path to the library. Ensure the process can load the plugin and its runtime dependencies; for example, install it in a system library path or add its directory to
LD_LIBRARY_PATH. - The library embeds an
occl-net-ibversion string. Release tooling sets it withOCCL_NET_IB_PLUGIN_VERSIONwhich follows the Major.Minor.Patch format. - Record that version with every production deployment and incident report.
- Basic port/link failover and recovery requires NCCL 2.20.3 or later.
- Full NIC failover and recovery requires NCCL 2.24.3 or later.
Check the plugin version
To extract the embedded version from a plugin, run:
readelf -p .occl_net_ib_version "/path/to/liboccl-net-occl-ib.so"If readelf is unavailable, use strings:
strings "/path/to/liboccl-net-occl-ib.so" | grep -F 'occl-net-ib version 'Replace the example path with the plugin library you will load. Look for occl-net-ib version <version> in the output. This is the OCCL-NET plugin version, not the application's NCCL runtime version.
Enable the plugin
Set NCCL_NET_PLUGIN to the complete path of the shared object. Use NCCL_NET=IB when the job must select the IB network transport explicitly.
export NCCL_NET_PLUGIN=/opt/occl-net/lib/liboccl-net-occl-ib.so
export NCCL_NET=IB
mpirun -np 16 ./your_applicationFor a launcher that propagates environment variables explicitly:
mpirun -np 16 \
-x NCCL_NET_PLUGIN=/opt/occl-net/lib/liboccl-net-occl-ib.so \
-x NCCL_NET=IB \
./your_applicationSet the same values on every rank. Do not mix plugin builds or incompatible NCCL runtimes within one job.
Confirm the plugin loaded
Enable NET and INIT information for one diagnostic run:
export NCCL_DEBUG=INFO
export NCCL_DEBUG_SUBSYS=INIT,NETThe NCCL host runtime, not the shared object by itself, prints the authoritative plugin-load records. With the settings above, expect these records, with the configured library path substituted for <path>:
NCCL_NET_PLUGIN set by environment to <path>
Successfully loaded external network plugin <path>
Initialized NET plugin IB
Assigned NET plugin IB to commThe second record proves that the runtime opened the library and found a supported exported NET-plugin ABI. Initialized proves that plugin initialization and device enumeration succeeded; Assigned proves that the IB plugin was selected for that communicator. The plugin then prints one or more device records in this form:
NET/IB: [<index>] <device>:<port>/<link-layer> provider=<provider>
speed=<speed> context=<pointer> pciPath=<path> ar=<0|1>
Treat all four runtime records plus at least one NET/IB device record as a successful load-and-selection confirmation. A useful minimum capture is stdout/stderr from every rank plus the plugin path, NCCL version, host name, and selected NIC list.
Trace a Built Library
For per-request and completion tracing, build the plugin with TRACE=1, then use:
export NCCL_DEBUG=TRACE
export NCCL_DEBUG_SUBSYS=NETFor per-request and completion tracing, the plugin needs to be built with TRACE=1, use liboccl-net-occl-ib-trace.so:
export NCCL_DEBUG=TRACE
export NCCL_DEBUG_SUBSYS=NET
NCCL_DEBUG=TRACE alone does not restore normal TRACE(...) statements if the plugin was built without ENABLE_TRACE.
Runtime configuration
The following variables are implemented by OCCL-NET's portable NET/IB code. Start with defaults unless a workload or troubleshooting procedure calls for a change.
| Variable | Default | Purpose |
|---|---|---|
NCCL_IB_HCA |
unset | Include or exclude the IB HCAs and ports visible to the job. Use it to constrain runs to known-good NICs. |
NCCL_IB_MERGE_NICS |
0 |
Merge compatible NICs into virtual devices when enabled. The default keeps NICs as separate devices. |
NCCL_IB_MERGE_VFS |
1 |
Merge compatible virtual functions. |
NCCL_IB_QPS_PER_CONNECTION |
1 |
Number of QPs per connection. |
NCCL_IB_SPLIT_DATA_ON_QPS |
0 |
Split data across QPs. |
NCCL_IB_ADAPTIVE_ROUTING |
auto | Override IB adaptive-routing selection. 0 disables it; 1 enables it where supported. |
NCCL_IB_AR_THRESHOLD |
8192 |
Message-size threshold for adaptive-routing behavior. |
NCCL_IB_TIMEOUT |
20 |
Verbs timeout used for QP connection configuration. |
NCCL_IB_RETRY_CNT |
7 |
Verbs retry count used for QP connection configuration. |
NCCL_IB_PKEY |
0 |
InfiniBand partition key. |
NCCL_IB_SL |
-1 |
Service-level override; otherwise traffic class/default policy applies. |
NCCL_IB_TC |
-1 |
Traffic-class override. |
NCCL_IB_FIFO_TC |
-1 |
FIFO traffic-class override. |
NCCL_IB_GID_INDEX |
-1 |
Force a GID index when automatic GID selection is unsuitable. |
NCCL_IB_ROCE_VERSION_NUM |
2 |
Requested RoCE version. |
NCCL_IB_ADDR_FAMILY |
unset | Limit bootstrap-address selection to an address family. |
NCCL_IB_ADDR_RANGE |
unset | Limit bootstrap-address selection to an IP range. |
NCCL_IB_ECE_ENABLE |
1 |
Enable ECE negotiation when available. |
NCCL_IB_PREPOST_RECEIVE_WORK_REQUESTS |
0 |
Pre-post receive WQEs. Resiliency enables required pre-posting automatically. |
NCCL_IB_RETURN_ASYNC_EVENTS |
1 |
Return fatal IB async events to the communicator. |
NCCL_IB_RESILIENCY_PORT_FAILOVER |
1 |
Enable QP/device failover and QP rejoin. |
NCCL_IB_RESILIENCY_PORT_FAILOVER_MAX_ATTEMPTS |
1 |
Maximum failed-request probe attempts. |
NCCL_IB_RESILIENCY_PORT_FAILOVER_PROBE_DELAY |
1000 ms |
Delay before posting a failover probe. |
OCI_FRM_ENABLE |
1 |
Enable OCCL-NET CIM/FRM congestion-aware steering. |
FRM_SPREAD_EPS_US |
4 |
FRM latency-spread threshold in microseconds. |
FRM_ZERO_STAMP_HOLDOFF |
2 |
FRM holdoff for zero latency stamps. |
NCCL_IB_WARN_RAIL_LOCAL |
0 |
Emit an INFO warning for local/remote rail mismatch. |
Values are process environment values. Prefer a job launcher, scheduler environment, or a controlled NCCL configuration file over shell profiles so a run is reproducible.
Recommended starting profiles
Default resilient/steered deployment:
export NCCL_NET_PLUGIN=/opt/occl-net/lib/liboccl-net-occl-ib.so
export NCCL_NET=IB
export NCCL_IB_RESILIENCY_PORT_FAILOVER=1
export OCI_FRM_ENABLE=1Simple compatibility profile with OCCL-NET still loaded:
export NCCL_NET_PLUGIN=/opt/occl-net/lib/liboccl-net-occl-ib.so
export NCCL_NET=IB
export OCI_FRM_ENABLE=0
export NCCL_IB_RESILIENCY_PORT_FAILOVER=0
export NCCL_IB_QPS_PER_CONNECTION=1
export NCCL_IB_SPLIT_DATA_ON_QPS=0
export NCCL_IB_MERGE_NICS=0
unset NCCL_NET_FORCE_MERGESee the following Troubleshooting section for an ordered isolation plan.
Full NIC Backup
Full NIC Backup uses NCCL_NET_FORCE_MERGE to place multiple physical devices in a backup group. OCCL-NET exposes GPU-local aliases for normal traffic and keeps the group's other members as warm standby paths. With NCCL_IB_RESILIENCY_PORT_FAILOVER=1, failed requests can move to those paths; the existing probe/rejoin mechanism can return traffic to a recovered primary.
Use NCCL 2.24.3 or newer and the same updated OCCL-NET build on every rank. NCCL 2.24.3–2.29 supports up to four members per group through NET ABI v9–v11; NCCL 2.30+ supports up to eight through v12. A backup group needs at least two members, all using the same link layer (InfiniBand or RoCE). Choose members with working peer connectivity and include a separate physical NIC so a whole-NIC failure leaves a usable path.
For a four-device group, start with:
export NCCL_NET_PLUGIN=/opt/occl-net/lib/liboccl-net-occl-ib.so
export NCCL_NET=IB
export NCCL_NET_FORCE_MERGE="mlx5_0,mlx5_1,mlx5_2,mlx5_3"
export NCCL_IB_RESILIENCY_PORT_FAILOVER=1
export NCCL_IB_QPS_PER_CONNECTION=1
export NCCL_DEBUG=INFO
export NCCL_DEBUG_SUBSYS=INIT,NETReplace the example names with devices visible on each host and propagate the configuration to every rank. NCCL_IB_HCA, if set, must allow the intended members.
The host runtime parses comma-separated members and semicolon-separated groups, for example NCCL_NET_FORCE_MERGE="mlx5_0,mlx5_1;mlx5_2,mlx5_3" creates two separate backup groups. Keep the quotes so the shell does not interpret the semicolon. Devices omitted from the list can still be selected or automatically merged; the variable is not a device filter. See NVIDIA's NIC Fusion syntax. Avoid duplicate members and overlapping groups.
The supported failure model is sequential/one-sided N-1: a group can retain a usable path as members fail, provided the corresponding peer paths remain reachable. Arbitrary simultaneous failures leaving unrelated survivors at opposite endpoints are outside this contract. Standby paths consume QP and registration resources; cross-NUMA backup traffic can reduce performance. In other words, Full NIC Backup is designed to handle successive device failures on one host, down to one surviving device in the group, while the peer’s corresponding network paths remain available. Recovery is not guaranteed when both hosts lose devices and their surviving devices lack a configured path between them.
Troubleshooting OCCL-NET
Use the following steps to isolate a problem without changing multiple variables at once. Apply one step to every rank, rerun the smallest reproducer, and record the exact result before moving to the next step.
Before changing configuration
Capture this information:
- Plugin path and embedded OCCL-NET version.
- NCCL version, application version, host names, rank-to-host mapping, and launcher command.
NCCL_*,OCI_FRM_*, andFRM_*variables used by the job.- Selected IB devices/ports, link state, link layer, and MTU.
- All rank logs with
NCCL_DEBUG=INFOandNCCL_DEBUG_SUBSYS=INIT,NET.
Do not begin with TRACE on a large production workload. It can make a failure harder to read and can materially increase output volume.
Progressive isolation sequence
The first successful step identifies the feature boundary crossed by the previous step. Keep all earlier changes in place while progressing.
| Step | Change | What it isolates |
|---|---|---|
| 0 | Run the known workload with the current settings and INFO NET logging. | Establishes the failure signature. |
| 1 | OCI_FRM_ENABLE=0 | CIM/FRM steering and its latency-driven QP selection. |
| 2 | NCCL_IB_RESILIENCY_PORT_FAILOVER=0 | Request replay, QP failover, probing, and QP rejoin. |
| 3 | NCCL_IB_QPS_PER_CONNECTION=1 and NCCL_IB_SPLIT_DATA_ON_QPS=0 | Multi-QP placement and split-data behavior. |
| 4 | Unset NCCL_NET_FORCE_MERGE and set NCCL_IB_MERGE_NICS=0. | Merged/virtual NIC topology and cross-rail selection. |
| 5 | NCCL_IB_ADAPTIVE_ROUTING=0 | IB adaptive-routing policy. |
| 6 | NCCL_IB_ECE_ENABLE=0 | ECE negotiation and reapplication during QP rejoin. |
| 7 | Set NCCL_IB_HCA to one known-good HCA/port. | Device/port or rail-specific failures. |
| 8 | NCCL_IB_RETURN_ASYNC_EVENTS=0 for a diagnostic comparison only. | Effect of propagating IB asynchronous fatal events. |
| 9 | NCCL_NET_PLUGIN=none | Entire OCCL-NET plugin. |
Step 8 is diagnostic only. Do not use it to mask a known device, CQ, QP, or GID health event in production.
Example isolation commands
Start with the plugin explicitly enabled:
export NCCL_NET_PLUGIN=/opt/occl-net/lib/liboccl-net-occl-ib.so
export NCCL_NET=IB
export NCCL_DEBUG=INFO
export NCCL_DEBUG_SUBSYS=INIT,NETDisable steering:
export OCI_FRM_ENABLE=0Disable failover/rejoin after that:
export NCCL_IB_RESILIENCY_PORT_FAILOVER=0Reduce to one non-merged, non-split QP configuration:
export NCCL_IB_QPS_PER_CONNECTION=1
export NCCL_IB_SPLIT_DATA_ON_QPS=0
unset NCCL_NET_FORCE_MERGE
export NCCL_IB_MERGE_NICS=0Finally, stop loading the plugin:
export NCCL_NET_PLUGIN=none
unset NCCL_NETIf the problem persists after Step 9, it is outside OCCL-NET's loaded plugin path. Continue with the application's NCCL, launcher, host networking, and hardware support procedures.
Symptom-to-evidence map
| Symptom | Look for | First isolation step |
|---|---|---|
| Plugin does not load | Missing shared-object path, incompatible plugin ABI, loader errors. | Verify path and library dependencies before Step 1. |
| Wrong NIC or incompatible link layer | NCCL_IB_HCA messages; incompatible-device WARNs. | 7 |
| Connection or QP setup failure | QP-created records, GID/RoCE settings, ibv_modify_qp errors. | 5, then 6, then 7 |
| CQE/QP fatal event | async fatal event on QP, Got CQE with error, peer/vendor/HCA fields. | 2, then 7 |
| Failover loop or permanent failure | Failed QP, replacement QP, probe/rejoin retry budget, permanent-error records. | 2 |
| Rejoin stalls | Local port is not active, Locally rebuilt QP, Waiting for peer-ready, peer-ready backoff. | 2, then 7 |
| Throughput regression or imbalance | FRM placement/latency output, per-QP skew, rail selection. | 1, then 3–5 |
| ECE-related connection or rejoin issue | ECE configuration or cached-ECE rejoin records. | 6 |
Full NIC Backup using NCCL_NET_FORCE_MERGE
Start with the Full NIC Backup profile and collect NCCL_DEBUG=INFO, NCCL_DEBUG_SUBSYS=INIT,NET logs from every rank. Confirm the plugin loaded before diagnosing backup behavior. Record the exact forced groups, HCA filter, QPs per connection, split-data setting, failover setting, plugin build, and NCCL runtime on both endpoints.
For four members arranged as two pairs with matching normalized PCI paths within each pair, expect alias creation like:
NET/IB : Made 2 GPU-local aliases for forced merge beginning at virtual device <index>A connection between paired aliases with QPs per connection set to one reports:
NET/IB: Force-merge negotiated activeWidth=2 Q=1 logicalQps=2 physicalQps=8 localPrivateDevices=4 peerPrivateDevices=4activeWidth is the number of active ports. logicalQps describes the traffic lanes; physicalQps includes their standby paths. localPrivateDevices and peerPrivateDevices show the backup membership at each endpoint. Alias counts and widths depend on PCI topology, so a single-port alias is not itself an error. The alias's name and speed do not list or sum its backup members.
| Symptom or log | Check and next action |
|---|---|
Skipping makeVDevice, NCCL_IB_MERGE_NICS=0 | Enable NCCL_IB_MERGE_NICS=1 along with the forced list on every rank. |
| No forced-alias creation or negotiation records | Check runtime/ABI support, a nonempty forced list, host device names, and whether NCCL_IB_HCA excluded members. Confirm the application selected the intended group. |
| Duplicate-device, overlapping-group, or incompatible-device warning | Use distinct members in disjoint groups with one link layer; respect the four-member v9–v11 or eight-member v12 limit. |
Incompatible force-merge connection protocol or mode, Incompatible legacy force-merge peer, or invalid geometry offer | Align plugin builds, forced-merge mode, and NCCL_IB_QPS_PER_CONNECTION on both peers. Older forced-merge builds are not wire-compatible with the new negotiation. |
Force-merge activeWidth=1 fallback: localPublicWidth=... peerPublicWidth=... | At least one alias has one active port. Check the device PCI paths and expected pairing; this fallback preserves backup membership. |
Force-merge activeWidth=1 fallback at 128-QP limit | Two active ports would exceed the per-connection cap. The plugin preserves configured Q and backup paths using one active port. Reduce Q if two-port operation is needed. |
Requested QP geometry exceeds the 128-QP connection limit | Even one active port exceeds the cap. Reduce Q or group size; activeWidth × Q × max(localPrivateDevices, peerPrivateDevices) must fit in 128. |
| Traffic fails instead of using a backup | Verify NCCL_IB_RESILIENCY_PORT_FAILOVER=1, negotiated membership, and reachable surviving paths. Capture CQE/async errors and replacement/probe/rejoin records. A second port on the failed physical NIC is not an independent backup. |
| Recovery stalls or bandwidth drops after failover | Follow the rejoin evidence in the symptom map. Check surviving-path connectivity, port state, and cross-NUMA placement. Full NIC Backup does not guarantee unchanged degraded bandwidth or arbitrary independent survivors at both endpoints. |
To isolate forced grouping while retaining failover, first unset NCCL_NET_FORCE_MERGE on every rank and rerun with the other settings unchanged. To remove merging entirely, also set NCCL_IB_MERGE_NICS=0. Remove persistent forced-merge entries from launcher/configuration files too. Setting the forced list to 0 is not an off switch. Restore the backup profile before evaluating failover; the progressive isolation sequence disables failover at step 2.
Keep configuration and log comparisons separate from hardware fault injection. For a backup incident, add the failure/recovery timeline and surviving devices on both endpoints to the escalation bundle. The supported model is sequential/one-sided N-1 with reachable peer paths, not arbitrary simultaneous bilateral NIC loss.
Escalation bundle
For a reproducible issue, include the smallest reproducer, complete logs from all ranks, the environment before and after each isolation step, plugin version, NCCL version, ibv_devinfo/port-state output, and whether the issue follows a specific HCA, port, host, rank, or message size.