NIC bonding combines multiple physical network interfaces into a single logical interface, providing link redundancy, increased throughput, or both — depending on the bonding mode selected. On RHEL 9, NetworkManager is the canonical tool for managing bonded interfaces, replacing the older ifcfg scripts. This tutorial covers creating a bond with nmcli, adding slave interfaces, assigning an IP address, and verifying bond status. Common bonding modes and a brief overview of the newer teaming subsystem are also explained.
Prerequisites
- RHEL 9 server with root or sudo access
- At least two physical or virtual network interfaces (e.g.,
ens3andens4) - NetworkManager running (
systemctl status NetworkManager) - Console or out-of-band access in case network connectivity is interrupted during configuration
Step 1 — Create the Bond Interface
Use nmcli to create the bond master connection. The bond.options parameter accepts a comma-separated list of kernel bonding module parameters. Here mode=active-backup provides simple failover (one interface active at a time) and miimon=100 checks link state every 100 milliseconds.
sudo nmcli con add
type bond
con-name bond0
ifname bond0
bond.options "mode=active-backup,miimon=100"
After this command, a new connection profile named bond0 exists in NetworkManager but no slave interfaces are attached yet and no IP is assigned.
Step 2 — Add Slave Interfaces to the Bond
Each physical NIC that will participate in the bond must be added as a slave (also called a port). Replace ens3 and ens4 with your actual interface names, which you can list with ip link show.
# Add first slave interface
sudo nmcli con add
type ethernet
slave-type bond
con-name bond0-slave1
ifname ens3
master bond0
# Add second slave interface
sudo nmcli con add
type ethernet
slave-type bond
con-name bond0-slave2
ifname ens4
master bond0
# Verify both slave connections were created
nmcli con show
Any existing connection profiles on ens3 or ens4 should be deactivated first to avoid IP address conflicts: sudo nmcli con down "Wired connection 1".
Step 3 — Assign a Static IP to the Bond
Configure the bond master with a static IPv4 address, default gateway, and DNS server. NetworkManager propagates this configuration to the kernel when the bond is brought up.
# Assign a static IP address and default gateway
sudo nmcli con mod bond0
ipv4.method manual
ipv4.addresses "192.168.1.50/24"
ipv4.gateway "192.168.1.1"
ipv4.dns "8.8.8.8,8.8.4.4"
# Bring up the bond and its slaves
sudo nmcli con up bond0
sudo nmcli con up bond0-slave1
sudo nmcli con up bond0-slave2
# Confirm the bond interface has the IP
ip addr show bond0
For DHCP instead of a static address, replace ipv4.method manual ipv4.addresses ... with ipv4.method auto.
Step 4 — Verify Bond Status via /proc
The kernel bond driver exposes detailed state information through the /proc virtual filesystem. This is the most reliable way to confirm which interface is currently active and whether link detection is functioning.
# Read live bond status from the kernel
cat /proc/net/bonding/bond0
The output shows the bonding mode, MII polling interval, which slave is currently active (Active Slave), and the link status of every member. A healthy output looks like this:
Ethernet Channel Bonding Driver: v5.x.x
Bonding Mode: fault-tolerance (active-backup)
Primary Slave: None
Currently Active Slave: ens3
MII Status: up
MII Polling Interval (ms): 100
...
Slave Interface: ens3
MII Status: up
...
Slave Interface: ens4
MII Status: up
To simulate a failover, bring down the active slave: sudo ip link set ens3 down. Re-reading /proc/net/bonding/bond0 should now show ens4 as the active slave.
Step 5 — Bonding Modes Reference
Choosing the right bonding mode depends on whether your switch supports LACP and whether you need load balancing or simple failover.
# mode=0 (balance-rr): Round-robin load balancing, no switch config needed
sudo nmcli con mod bond0 bond.options "mode=balance-rr,miimon=100"
# mode=1 (active-backup): One active link, failover only — switch-agnostic
sudo nmcli con mod bond0 bond.options "mode=active-backup,miimon=100"
# mode=4 (802.3ad LACP): IEEE standard aggregation — requires LACP-capable switch
sudo nmcli con mod bond0 bond.options "mode=802.3ad,miimon=100,lacp_rate=fast"
# mode=5 (balance-tlb): Adaptive transmit load balancing, no switch config
sudo nmcli con mod bond0 bond.options "mode=balance-tlb,miimon=100"
# Apply changes by restarting the bond
sudo nmcli con down bond0 && sudo nmcli con up bond0
active-backup is the safest choice for servers with unmanaged switches. 802.3ad (LACP) delivers true bidirectional load balancing but requires switch-side configuration. balance-rr can cause out-of-order TCP packets without LACP, so it is best suited for non-TCP workloads.
Step 6 — Teaming as an Alternative
Linux teaming is a userspace alternative to kernel bonding, configured via the teamd daemon and also supported by NetworkManager. It provides the same functionality as bonding but uses a JSON-based runner configuration.
# Create a team interface with the activebackup runner
sudo nmcli con add
type team
con-name team0
ifname team0
team.runner activebackup
# Add a port to the team
sudo nmcli con add
type ethernet
slave-type team
con-name team0-port1
ifname ens3
master team0
# Check team state
sudo teamdctl team0 state
For most RHEL 9 deployments, bonding is preferred over teaming because it is kernel-native and requires no additional daemon. Teaming may be chosen when more granular per-port policies are needed.
Conclusion
You have created a bonded interface on RHEL 9 using nmcli, attached two slave NICs, assigned a static IP, and verified link state through /proc/net/bonding/bond0. Understanding the different bonding modes lets you match the configuration to your network switch capabilities and availability requirements.
Next steps: How to Set Up Pacemaker and Corosync for High Availability on RHEL 9, How to Configure VLAN Tagging with 802.1Q on RHEL 9, and How to Configure BGP Routing with BIRD on RHEL 9.