NMState Bond LACP Configuration OpenShift
Configure LACP bonding with NMState on OpenShift. NodeNetworkConfigurationPolicy for 802.3ad bonds, VLAN tagging, and storage network bonds.
π‘ Quick Answer: Use NMStateβs
NodeNetworkConfigurationPolicy(NNCP) to configure LACP bonds on OpenShift nodes declaratively. Setmode: 802.3ad,options.xmit_hash_policy: layer3+4(critical for NFS/storage traffic distribution), andoptions.miimon: 100for link monitoring. NMState applies the config via NetworkManager and reconciles drift automatically.
The Problem
Bare-metal OpenShift nodes need link aggregation for:
- Storage network bandwidth (NFS, iSCSI, Ceph)
- Redundancy β survive single link failure
- GPU/RDMA traffic distribution across multiple NICs
- Separation of management, storage, and compute networks
Manual bonding with nmcli or MachineConfig is fragile and doesnβt reconcile drift. NMState makes it declarative.
The Solution
Basic LACP Bond
apiVersion: nmstate.io/v1
kind: NodeNetworkConfigurationPolicy
metadata:
name: bond-storage
spec:
nodeSelector:
node-role.kubernetes.io/worker: ""
desiredState:
interfaces:
- name: bond0
type: bond
state: up
ipv4:
address:
- ip: 10.30.0.0
prefix-length: 24
dhcp: false
enabled: true
ipv6:
enabled: false
link-aggregation:
mode: 802.3ad
port:
- ens3f0
- ens3f1
options:
xmit_hash_policy: layer3+4 # Distributes NFS traffic across links
lacp_rate: fast # LACPDU every 1s (vs 30s for slow)
miimon: "100" # Link check every 100ms
ad_select: bandwidth # Select active aggregator by bandwidthWhy layer3+4 is critical for storage:
| Hash Policy | Distributes By | NFS Problem |
|---|---|---|
layer2 | MAC address | Single TCP connection = single link |
layer2+3 | MAC + IP | Same problem for single server |
layer3+4 | IP + port | Each NFS mount uses different source port β distributes |
LACP Bond with VLAN
apiVersion: nmstate.io/v1
kind: NodeNetworkConfigurationPolicy
metadata:
name: bond-storage-vlan
spec:
nodeSelector:
node-role.kubernetes.io/worker: ""
desiredState:
interfaces:
# Bond interface (no IP)
- name: bond0
type: bond
state: up
ipv4:
enabled: false
link-aggregation:
mode: 802.3ad
port:
- ens3f0
- ens3f1
options:
xmit_hash_policy: layer3+4
miimon: "100"
# VLAN on top of bond
- name: bond0.100
type: vlan
state: up
vlan:
base-iface: bond0
id: 100
ipv4:
address:
- ip: 10.30.0.0
prefix-length: 24
dhcp: false
enabled: truePer-Node IP Assignment
# Use node-specific NNCPs for different IPs
apiVersion: nmstate.io/v1
kind: NodeNetworkConfigurationPolicy
metadata:
name: bond-storage-worker-1
spec:
nodeSelector:
kubernetes.io/hostname: worker-1
desiredState:
interfaces:
- name: bond0
type: bond
state: up
ipv4:
address:
- ip: 10.30.0.11
prefix-length: 24
dhcp: false
enabled: true
link-aggregation:
mode: 802.3ad
port:
- ens3f0
- ens3f1
options:
xmit_hash_policy: layer3+4
miimon: "100"
---
apiVersion: nmstate.io/v1
kind: NodeNetworkConfigurationPolicy
metadata:
name: bond-storage-worker-2
spec:
nodeSelector:
kubernetes.io/hostname: worker-2
desiredState:
interfaces:
- name: bond0
type: bond
state: up
ipv4:
address:
- ip: 10.30.0.12
prefix-length: 24
dhcp: false
enabled: true
link-aggregation:
mode: 802.3ad
port:
- ens3f0
- ens3f1
options:
xmit_hash_policy: layer3+4
miimon: "100"Verify Bond Status
# Check NNCP status
oc get nncp
# NAME STATUS REASON
# bond-storage Available SuccessfullyConfigured
# Check NodeNetworkState
oc get nns worker-1 -o yaml | yq '.status.currentState.interfaces[] | select(.name == "bond0")'
# On the node directly
oc debug node/worker-1 -- chroot /host cat /proc/net/bonding/bond0
# Ethernet Channel Bonding Driver: v6.1.0
# Bonding Mode: IEEE 802.3ad Dynamic link aggregation
# Transmit Hash Policy: layer3+4 (1)
# LACP rate: fast
#
# Slave Interface: ens3f0
# MII Status: up
# Speed: 25000 Mbps
# Link Failure Count: 0
# 802.3ad info:
# LACP active: active
#
# Slave Interface: ens3f1
# MII Status: up
# Speed: 25000 Mbps
# Verify LACP partner (switch must also be configured)
oc debug node/worker-1 -- chroot /host \
cat /proc/net/bonding/bond0 | grep "Partner Mac"
# Partner Mac Address: 00:1a:2b:3c:4d:5e β Switch MACNFS with nconnect on Bond
# Critical: Use nconnect to utilize bond bandwidth
# Single TCP connection can't exceed one link's speed
# Mount with nconnect=8 (8 TCP connections β distributes across bond)
mount -t nfs -o nconnect=8,vers=4.1 10.30.0.1:/export/data /mnt/data
# In Kubernetes PV:
# mountOptions:
# - nconnect=8
# - vers=4.1Without nconnect, a single NFS mount uses one TCP connection β one bond member β 25 Gbps max even with 2Γ25 Gbps bond.
Common Issues
NNCP stuck in βProgressingβ forever
NetworkManager canβt apply the config. Check NMState handler logs: oc logs -n openshift-nmstate ds/nmstate-handler. Common cause: port interface names donβt match actual NIC names on the node.
Bond created but no LACP partner
Switch ports not configured for LACP. Verify switch-side: channel-group mode active, LACP rate matches. Check Partner Mac Address in /proc/net/bonding/bond0 β empty means no LACP negotiation.
Bond falls back to single link
lacp_rate: slow (default 30s) can cause timeouts. Use fast for 1s LACPDU interval. Also check ad_select: bandwidth to prefer the aggregator with most links.
NFS throughput not exceeding single link speed
Missing nconnect mount option. Each TCP connection hashes to one bond member. nconnect=8 creates 8 connections β layer3+4 distributes them.
Best Practices
xmit_hash_policy: layer3+4β only policy that distributes NFS/storage trafficnconnect=8for NFS β critical for utilizing bond bandwidthlacp_rate: fastβ 1s LACPDU for faster failover detectionmiimon: 100β check link every 100ms- Match switch LACP config β both sides must agree on mode and rate
- Use NNCP not MachineConfig β NMState reconciles drift, MC is one-shot
Key Takeaways
- NMState NNCP makes LACP bonding declarative and drift-resistant on OpenShift
802.3admode requires matching LACP configuration on the switchlayer3+4hash policy is mandatory for distributing storage (NFS) traffic across bond membersnconnect=8on NFS mounts is required to actually use the bond bandwidth- NMState applies config via NetworkManager and continuously reconciles
- Per-node NNCPs with
nodeSelectorhandle different IP assignments

Recommended
Kubernetes Recipes β The Complete Book100+ production-ready patterns with detailed explanations, best practices, and copy-paste YAML. Everything in one place.
Get the Book βLearn by Doing
CopyPasteLearn β Hands-on Cloud & DevOps CoursesMaster Kubernetes, Ansible, Terraform, and MLOps with interactive, copy-paste-run lessons. Start free.
Browse Courses βπ Deepen Your Skills β Hands-on Courses
Courses by CopyPasteLearn.com β Learn IT by Doing
