Octet

A server has a 2 x 10G LACP bond but one big transfer never goes above 10 Gbps, and all traffic to the gateway uses one link. Why?

Show the answer

Say this first

LACP balances by flow, not by packet, so one TCP connection always rides one member link and is capped at 10G. On top of that the default xmit_hash_policy is layer2, which hashes only MAC addresses. Every routed packet has the gateway's MAC as destination, so with layer2 all off-subnet traffic picks the same link. layer3+4 hashes IPs and ports and spreads many flows across both links. Inbound balance is decided by the switch's own hash.

Go deeper

See the policy and the per-link load

Output
$ grep -E 'Mode|Hash' /proc/net/bonding/bond0
Bonding Mode: IEEE 802.3ad Dynamic link aggregation
Transmit Hash Policy: layer2 (0)
$ ip -s link show ens1f0 | grep -A1 TX
$ ip -s link show ens1f1 | grep -A1 TX

One member's TX counters climbing and the other idle is the symptom.

Change it

Shell
ip link set bond0 type bond xmit_hash_policy layer3+4

Netplan: transmit-hash-policy: layer3+4 under the bond's parameters. The kernel documentation notes layer3+4 is not strictly 802.3ad compliant because fragments of one packet may take different links, which is harmless in practice.

The switch side

Return traffic is balanced by the switch. On a Catalyst, show etherchannel load-balance shows the method; port-channel load-balance src-dst-ip (or a mixed IP and port method where supported) avoids the same trap on the way in.

What does give more than 10G to one transfer

Several parallel flows (multi-stream copies, iperf3 -P 4), a faster single link, or mode 0 at the cost of TCP reordering. LACP never splits one flow.

Traps

  • Promising 20G for a single flow on a 2 x 10G bond.
  • Leaving layer2 hashing on a server whose traffic all goes through one gateway.
How did you do?