FreeBSD Link Aggregation with lagg(4)¶
lagg(4) combines several physical interfaces into one logical interface, for redundancy (a cable, NIC or switch port can fail without dropping the host) and, depending on the protocol, more aggregate bandwidth. It's FreeBSD's equivalent of Linux bonding/teaming.
1. Choosing a Protocol¶
laggproto |
What it does | Switch config needed | Linux bonding equivalent |
|---|---|---|---|
lacp |
IEEE 802.3ad/802.1AX. Negotiates the bundle with the switch; hashes flows across active ports; drops failed links automatically | LACP port-channel (active or passive) on the switch | mode=802.3ad (mode 4) |
failover |
All traffic on the primary port; moves to the next port if the primary loses link. Primary is the first laggport added |
None (ports can even go to different switches) | mode=active-backup (mode 1) |
loadbalance |
Static hash of each flow across all ports, no negotiation | Static port-channel / EtherChannel ("mode on") | mode=balance-xor (mode 2) |
roundrobin |
Sends packets across ports in turn; can reorder packets within a flow | Static port-channel | mode=balance-rr (mode 0) |
broadcast |
Sends every packet out every port | Depends on use; rarely what you want | mode=broadcast (mode 3) |
none |
Disables traffic on the lagg; useful while reconfiguring | - | - |
Rules of thumb:
- Use
lacpwhenever the switch supports it. It's the only mode where both ends agree on which links are in the bundle, so a miscabled or misconfigured port is taken out of service instead of black-holing traffic. - Use
failoverfor an unmanaged switch, ports split across two switches without MLAG, or a laptop failing over from wired to Wi-Fi. - Avoid
loadbalanceandroundrobinunless you need them for something specific: without negotiation, a port that's up but miswired or misconfigured on the switch still receives traffic.
Any single flow (one TCP connection) still uses one link with lacp and loadbalance, so a single file copy won't go faster than one NIC. Aggregation helps with many concurrent flows.
2. Persistent Configuration in /etc/rc.conf¶
The member interfaces are brought up with no address of their own; the address lives on the lagg. The examples use igb0 and igb1 - substitute your driver names (ifconfig -l lists them).
2.1 LACP¶
# /etc/rc.conf
ifconfig_igb0="up"
ifconfig_igb1="up"
cloned_interfaces="lagg0"
ifconfig_lagg0="laggproto lacp laggport igb0 laggport igb1 192.168.10.20/24"
defaultrouter="192.168.10.1"
2.2 Failover¶
# /etc/rc.conf
ifconfig_igb0="up"
ifconfig_igb1="up"
cloned_interfaces="lagg0"
ifconfig_lagg0="laggproto failover laggport igb0 laggport igb1 192.168.10.20/24"
defaultrouter="192.168.10.1"
igb0 is the primary because it's listed first. Traffic moves back to it when its link returns.
2.3 Static load balancing¶
The original form of this config, as found in older notes, used loadbalance across two Broadcom bce ports:
# /etc/rc.conf
ifconfig_bce0="up"
ifconfig_bce1="up"
cloned_interfaces="lagg0"
ifconfig_lagg0="laggproto loadbalance laggport bce0 laggport bce1 192.168.10.20/24"
This only works correctly if the switch ports are configured as a static port-channel. If the switch supports LACP, change loadbalance to lacp and configure an LACP port-channel instead.
2.4 DHCP on a lagg¶
ifconfig_lagg0="laggproto lacp laggport igb0 laggport igb1 DHCP"
2.5 Using sysrc instead of editing by hand¶
sysrc ifconfig_igb0="up" ifconfig_igb1="up"
sysrc cloned_interfaces+="lagg0"
sysrc ifconfig_lagg0="laggproto lacp laggport igb0 laggport igb1 192.168.10.20/24"
The += appends to cloned_interfaces without clobbering existing entries such as bridges or VLANs.
2.6 Apply¶
service netif restart && service routing restart
Do this from the console (or IPMI/serial), not over SSH on the interfaces you're changing - if the switch side isn't ready yet, you'll lose the session.
3. Runtime Configuration (Testing Without a Reboot)¶
Build the lagg by hand first to prove the switch side works, then copy the working settings into rc.conf:
ifconfig igb0 up
ifconfig igb1 up
ifconfig lagg0 create
ifconfig lagg0 up laggproto lacp laggport igb0 laggport igb1 192.168.10.20/24
route add default 192.168.10.1
Change things on the fly:
ifconfig lagg0 -laggport igb1 # remove a member
ifconfig lagg0 laggport igb1 # add it back
ifconfig lagg0 laggproto failover # switch protocol
ifconfig lagg0 destroy # tear it all down
The lagg module (if_lagg) loads automatically when lagg0 is created, so you don't need a custom kernel or a kld_list entry.
4. VLANs on Top of a lagg¶
The common server pattern: an LACP bundle to the switch carrying several tagged VLANs.
# /etc/rc.conf
ifconfig_igb0="up"
ifconfig_igb1="up"
cloned_interfaces="lagg0"
ifconfig_lagg0="laggproto lacp laggport igb0 laggport igb1 up"
vlans_lagg0="10 20"
ifconfig_lagg0_10="inet 10.0.10.5/24"
ifconfig_lagg0_20="inet 10.0.20.5/24"
defaultrouter="10.0.10.1"
This creates lagg0.10 and lagg0.20. The lagg itself carries no address (up only), and the switch port-channel must be a trunk allowing VLANs 10 and 20. The same lagg can also be a member of a bridge(4) for VNET jails or bhyve guests - see the VNET section of the jails guide.
5. Wired-to-Wireless Failover (Laptops)¶
A failover lagg can move a laptop between Ethernet and Wi-Fi without dropping connections. Wireless interfaces can't change their MAC address the way Ethernet can, so give the wired NIC the wireless card's MAC:
# /etc/rc.conf
ifconfig_em0="ether 00:00:5e:00:53:01 up" # set to wlan0's MAC address
wlans_iwm0="wlan0"
ifconfig_wlan0="WPA"
create_args_wlan0="country CA"
cloned_interfaces="lagg0"
ifconfig_lagg0="up laggproto failover laggport em0 laggport wlan0 DHCP"
Get the wireless MAC from ifconfig wlan0 | grep ether and replace the placeholder. Wired (em0) is primary because it's listed first.
6. Switch Side¶
Example for a Cisco IOS-style switch; other vendors use similar concepts (port-channel, LAG, trunk group, bond).
LACP (laggproto lacp):
interface range GigabitEthernet1/0/1 - 2
channel-group 1 mode active
!
interface Port-channel1
switchport mode access
switchport access vlan 10
Static (laggproto loadbalance or roundrobin):
interface range GigabitEthernet1/0/1 - 2
channel-group 1 mode on
Failover: no special switch config; leave the ports as ordinary access or trunk ports with identical VLAN settings.
Keep speed, duplex, MTU and VLAN settings identical on every member port, on both ends.
7. Verification¶
ifconfig lagg0
A healthy LACP bundle shows each port as active, collecting and distributing:
lagg0: flags=1008843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500
options=...
ether 00:00:5e:00:53:10
inet 192.168.10.20 netmask 0xffffff00 broadcast 192.168.10.255
laggproto lacp lagghash l2,l3,l4
laggport: igb0 flags=1c<ACTIVE,COLLECTING,DISTRIBUTING>
laggport: igb1 flags=1c<ACTIVE,COLLECTING,DISTRIBUTING>
status: active
For failover, the primary shows MASTER,ACTIVE and the backup shows no flags until it takes over.
Useful checks:
ifconfig -v lagg0 # extra LACP detail: partner system ID, keys, port states
netstat -I igb0 -w 1 # per-member traffic, to confirm both links carry load
netstat -I igb1 -w 1
dmesg | grep -i lagg # link state changes and LACP events
Test failover deliberately: start a long ping to the gateway, then unplug one cable (or ifconfig igb0 down). You should see at most a lost packet or two, the port drop out of ifconfig lagg0, and traffic continue on the other link. Plug it back in and confirm it rejoins.
8. Tuning¶
ifconfig lagg0 lagghash l3,l4 # hash on IP + port only (default is l2,l3,l4)
ifconfig lagg0 lacp_fast_timeout # 1s LACP PDUs instead of 30s - faster detection of a dead partner
ifconfig lagg0 mtu 9000 # jumbo frames; applied to all members, switch must match
Put these in the ifconfig_lagg0 line in rc.conf to make them persistent, for example:
ifconfig_lagg0="laggproto lacp lacp_fast_timeout laggport igb0 laggport igb1 192.168.10.20/24 mtu 9000"
Failover receive behaviour: by default a failover lagg only accepts traffic on the active port. Set sysctl net.link.lagg.failover_rx_all=1 (persist in /etc/sysctl.conf) to accept traffic arriving on any member, which helps with switches that are slow to update their MAC tables.
9. Troubleshooting¶
| Symptom | Likely cause | Fix |
|---|---|---|
LACP ports show no COLLECTING,DISTRIBUTING flags |
Switch ports not in an LACP port-channel, or channel in mode on (static) |
Configure channel-group N mode active (or passive) on the switch |
status: no carrier on lagg0 |
All members down, or none accepted into the bundle | Check ifconfig igb0/igb1 link state, cables, and switch port status |
Intermittent loss with loadbalance/roundrobin |
Switch not configured for a static port-channel, so it sees the same MAC flapping between ports | Configure a static channel, or switch both ends to LACP |
| Only one link ever carries traffic | Expected for a single flow; or hash inputs too narrow for your traffic | Test with many flows; try lagghash l3,l4 |
| Members join with mismatched speed | Mixed 1G/10G NICs or auto-negotiation mismatch | LACP only aggregates ports of equal speed; match NICs and switch settings |
| Config works by hand but not at boot | rc.conf typo, or members missing ifconfig_<if>="up" |
Check with service netif restart from the console and read /var/log/messages |
| Lost SSH while reconfiguring | Changed the interface carrying the session | Work from console/IPMI, or keep a separate management NIC |
References¶
- FreeBSD Handbook: Link Aggregation and Failover
man 4 lagg,man 8 ifconfig,man 5 rc.conf,man 4 vlan