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-ib version string. Release tooling sets it with OCCL_NET_IB_PLUGIN_VERSION which 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_application

For 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_application

Set 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,NET

The 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 comm

The 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=NET

For 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.

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,NET

Replace 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_*, and FRM_* variables used by the job.
  • Selected IB devices/ports, link state, link layer, and MTU.
  • All rank logs with NCCL_DEBUG=INFO and NCCL_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.

StepChangeWhat it isolates
0Run the known workload with the current settings and INFO NET logging.Establishes the failure signature.
1OCI_FRM_ENABLE=0CIM/FRM steering and its latency-driven QP selection.
2NCCL_IB_RESILIENCY_PORT_FAILOVER=0Request replay, QP failover, probing, and QP rejoin.
3NCCL_IB_QPS_PER_CONNECTION=1 and NCCL_IB_SPLIT_DATA_ON_QPS=0Multi-QP placement and split-data behavior.
4Unset NCCL_NET_FORCE_MERGE and set NCCL_IB_MERGE_NICS=0.Merged/virtual NIC topology and cross-rail selection.
5NCCL_IB_ADAPTIVE_ROUTING=0IB adaptive-routing policy.
6NCCL_IB_ECE_ENABLE=0ECE negotiation and reapplication during QP rejoin.
7Set NCCL_IB_HCA to one known-good HCA/port.Device/port or rail-specific failures.
8NCCL_IB_RETURN_ASYNC_EVENTS=0 for a diagnostic comparison only.Effect of propagating IB asynchronous fatal events.
9NCCL_NET_PLUGIN=noneEntire 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,NET

Disable steering:

export OCI_FRM_ENABLE=0

Disable failover/rejoin after that:

export NCCL_IB_RESILIENCY_PORT_FAILOVER=0

Reduce 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=0

Finally, stop loading the plugin:

export NCCL_NET_PLUGIN=none
                        unset NCCL_NET

If 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

SymptomLook forFirst isolation step
Plugin does not loadMissing shared-object path, incompatible plugin ABI, loader errors.Verify path and library dependencies before Step 1.
Wrong NIC or incompatible link layerNCCL_IB_HCA messages; incompatible-device WARNs.7
Connection or QP setup failureQP-created records, GID/RoCE settings, ibv_modify_qp errors.5, then 6, then 7
CQE/QP fatal eventasync fatal event on QP, Got CQE with error, peer/vendor/HCA fields.2, then 7
Failover loop or permanent failureFailed QP, replacement QP, probe/rejoin retry budget, permanent-error records.2
Rejoin stallsLocal port is not active, Locally rebuilt QP, Waiting for peer-ready, peer-ready backoff.2, then 7
Throughput regression or imbalanceFRM placement/latency output, per-QP skew, rail selection.1, then 3–5
ECE-related connection or rejoin issueECE 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=4

activeWidth 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 logCheck and next action
Skipping makeVDevice, NCCL_IB_MERGE_NICS=0Enable NCCL_IB_MERGE_NICS=1 along with the forced list on every rank.
No forced-alias creation or negotiation recordsCheck 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 warningUse 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 offerAlign 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 limitTwo 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 limitEven 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 backupVerify 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 failoverFollow 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.