Andrew Mercer
on this page

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 lacp whenever 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 failover for an unmanaged switch, ports split across two switches without MLAG, or a laptop failing over from wired to Wi-Fi.
  • Avoid loadbalance and roundrobin unless 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