Latest / Linux Server Admin with Fexingo: Sysadmin, Bash, and Server Engineering / How to Set Up Linux Server Network Bonding with Teamd
Transcript
- Lucas: You've got a web server that needs to stay up even when a network cable gets kicked out by the cleaning crew — or a switch port dies. The answer isn't buying a second server. It's bonding two network interfaces together so the server keeps running over the remaining link. Luna: Right — network bonding. We've talked about hardware RAID for disks, but the network side of redundancy doesn't get as much airtime. Lucas: Exactly. And there's a modern way to do it on Linux that's replaced the old bonding module for many distros — it's called teamd. Instead of loading the kernel bonding driver directly, you use a userspace daemon that manages the team of interfaces. Luna: So teamd is like a smarter, more flexible bonding manager? What's the big advantage over the old bond driver? Lucas: The main one is that teamd implements the Link Aggregation Control Protocol, or LACP, in userspace, so you can update it without a kernel recompile. It also has a cleaner architecture — each port is managed by a separate plugin, which makes it easier to extend. Red Hat adopted it as the default for RHEL 7 and later, and it's been solid. Luna: Before we go further — a quick note. We keep these shows ad-free and listener-supported, and it genuinely costs a couple of dollars a month per listener to run the servers and editing tools. If today's tech conversation gave you something usable, buy me a coffee dot com slash fexingo makes a real difference. Lucas: Yeah, it's that simple — and it keeps us independent, so we can drill into topics like this without chasing sponsors. Thanks to anyone who's chipped in. Luna: Alright — back to the bonds. So teamd — how do you actually set it up? Start with the pieces. Lucas: You need at least two physical NICs — let's say enp3s0 and enp4s0. On a CentOS Stream 9 server, the teamd package is in the base repo. Install it with 'yum install teamd' — that pulls in the daemon and the teamdctl control tool. Then you need to create a configuration JSON file that defines the team interface. Luna: JSON — so it's declarative? That's cleaner than editing a bunch of sysfs files. Lucas: Exactly. Here's a minimal config for active-backup mode — one link active, the other standing by. The JSON looks like this: {"device": "team0", "runner": {"name": "activebackup"}, "ports": {"enp3s0": {}, "enp4s0": {}}}. You save that to a file, say /etc/teamd/team0.conf. Then run 'teamd -d -c /etc/teamd/team0.conf -t team0' to start the daemon. Luna: And that gives you a team0 interface that's basically a virtual NIC with the MAC of the first port? Lucas: Close — it uses the MAC of the first port added unless you override it. Now you assign an IP address to team0, just like any other interface. 'ip addr add 192.168.1.100/24 dev team0', 'ip link set team0 up'. And you're live — traffic flows through enp3s0. If that link drops, teamd automatically fails over to enp4s0 within a few seconds. Luna: That's the active-backup mode. But what if you want to use both NICs at the same time for higher throughput? Lucas: Then you'd use a load-balancing runner. The most common is 'loadbalance' — it uses a hash of the packet headers to distribute flows across ports. The JSON changes the runner name to 'loadbalance', and you optionally add a 'tx_hash' policy. But there's a catch: to get full utilization of both links, you usually need LACP negotiation with the switch — that's the 'lacp' runner. Luna: And the switch needs to support LACP and have the ports configured as a LAG — Link Aggregation Group. So it's not just a server-side change. Lucas: Right. If the switch isn't configured for LACP, you can still use 'loadbalance' without LACP — it'll distribute egress traffic based on the hash, but the switch sees two independent links, so inbound traffic might not balance. For most server to server traffic, that's fine. But for high-availability setups where you want both redundancy and throughput, LACP is the standard. Luna: Let's talk about monitoring. How do you check the status of a team? Lucas: The primary tool is teamdctl. Run 'teamdctl team0 state' — it dumps the current configuration and the state of each port: which one is active, link status, and counters. You can also do 'teamdctl team0 port list' for a quick view. And if you need to force a failover for testing, 'teamdctl team0 port config update enp3s0 link_watch' can simulate a link down. Luna: That's great for testing without actually yanking a cable. What about persistent configuration — making it survive a reboot? Lucas: You have two paths. One is to use NetworkManager — it has native team support. You create a connection profile for team0 and add the ports as slave connections. The other is to use systemd-networkd with netdev and link files. On CentOS, NetworkManager is the default, so I'd recommend that route for most people. Luna: Walk us through the NetworkManager approach quickly. Lucas: Sure. First, stop any running teamd instance. Then use nmcli: 'nmcli connection add type team con-name team0 ifname team0 config /etc/teamd/team0.conf'. That imports your JSON config. Then add the ports: 'nmcli connection add type team-slave con-name team0-port1 ifname enp3s0 master team0' and similarly for enp4s0. Then bring it up: 'nmcli connection up team0'. NetworkManager handles the teamd daemon automatically from there. Luna: So the JSON config gets embedded into the NetworkManager profile. That means you can manage it with all the usual nmcli commands — change IP, DNS, routing. Lucas: Exactly. And the failover behavior remains the same. One thing to watch: if you're using DHCP, the team interface gets its IP from DHCP, not the individual ports. The ports themselves don't have IPs — they're just raw links. Luna: That's important — people might accidentally assign IPs to the slave interfaces and cause routing conflicts. Now, what about performance? Does teamd add latency? Lucas: In practice, the overhead is negligible — we're talking single-digit microseconds. The teamd daemon does link monitoring via a configurable interval, default 100 milliseconds. For most workloads, that's fine. If you need faster failover, you can lower the interval, but that increases CPU usage slightly. For a typical web server or database, the default is fine. Luna: We should mention that teamd supports multiple runners besides activebackup and loadbalance. There's 'broadcast' — sends every packet out every port — and 'roundrobin' — sends packets in a round-robin fashion. But those are less common. Lucas: Right. Broadcast is useful for specific multicast scenarios, and roundrobin can cause out-of-order packets, so it's rarely used. The two you'll actually deploy are activebackup for pure redundancy and loadbalance with or without LACP for throughput. Luna: Let's talk about a real-world scenario. Say you have an NFS server with two 1 GbE NICs. You want redundancy but also want to aggregate bandwidth for multiple clients. How would you set that up? Lucas: I'd use loadbalance runner without LACP, because most NFS clients don't need LACP — the server-side hash will distribute NFS connections across both links. Each client gets a single TCP connection, which goes over one port, but different clients land on different ports. So you get near 2 Gbps total throughput if you have enough clients. For redundancy, if one link fails, the active connections on that port drop — NFS retransmits, and the new connections go over the remaining link. Luna: But the dropped connections are the downside of non lacp load balancing. With activebackup, no connections drop — just a brief pause during failover. Lucas: Correct. That's the trade-off: throughput vs seamless failover. For a web server serving stateless HTTP, dropped connections are fine — the client retries. For a database or NFS with stateful writes, you might prefer activebackup and accept the single-link throughput limit. Luna: And if you need both? You go with LACP — that gives you load balancing across both links and, because the switch is part of the negotiation, failover is handled at the link level without losing the LAG. Lucas: Exactly. But LACP requires switch configuration, and not all switches support it. For a small office or lab, activebackup or simple loadbalance is perfectly fine. Luna: One more thing — teamd has a 'link_watch' feature that can ping a gateway to detect upstream failures, not just local link loss. That's a step beyond the old bonding driver. Lucas: Yeah, that's a killer feature. You configure a 'link_watch' section in the JSON with a target IP, and teamd will consider the link down if that IP becomes unreachable — even if the local NIC still shows carrier. That catches cases like a switch that's powered on but has a dead uplink. Luna: So you can do 'arp_ping' or 'nsna_ping' for IPv6. That's enterprise-grade failover detection. Lucas: Exactly. Let me give you a sample JSON with that: {"device": "team0", "runner": {"name": "activebackup"}, "link_watch": {"name": "arp_ping", "interval": 1000, "missed_max": 3, "target_host": "192.168.1.1"}, "ports": {"enp3s0": {}, "enp4s0": {}}}. This pings the gateway every second, and after three misses, it switches ports. Luna: That's solid. I think we've covered enough for someone to get started. Any final gotchas? Lucas: One: make sure both ports are connected to the same broadcast domain — same VLAN, same subnet. Two: if you're using NetworkManager, don't also run a manual teamd instance — they'll conflict. Three: test failover by actually pulling a cable or disabling a port with 'ip link set enp3s0 down'. Don't just rely on teamdctl. Luna: Good advice. So teamd gives you a flexible, modern way to bond NICs — whether you need redundancy or throughput, it's worth learning. Lucas: And it's already in the repos — no extra software to buy. That's the kind of reliability that keeps a server room running.