How to Simulate Bandwidth Limits and High Packet Loss Locally on Linux Using TC
Learn how to test the resilience of distributed applications under real network conditions using the native Linux kernel network emulator, the tc utility.
Summary
- Simulating severe network constraints directly within the development environment eliminates surprises in geographically dispersed production systems.
- The Netem subsystem operates directly at the Linux kernel link layer to inject latency, jitter, and packet loss in a controlled manner.
- Defining fine-grained bandwidth limits requires the combined use of HTB queueing disciplines and the Netem extension.
- Immediate removal of applied rules prevents stress tests from corrupting long-running administrative connections on the local machine.
- Empirical validation of timeout-based protocols reveals structural flaws invisible in high-speed local connections.
The Invisible Challenge of Resilience in Imperfect Networks
Developing software in local environments connected by high-speed fiber optic cables creates a false sense of operational security. In practice, the global internet infrastructure is chaotic, full of unstable mobile connections, congested routes, and intermittent drops of data packets. When a distributed system fails to handle these variations, the end user experiences frozen screens, duplicate requests, and corrupted data. Software engineers need tools capable of reproducing this network chaos directly on their development workstation.
Instead of relying on expensive remote servers or cloud simulations that are difficult to orchestrate, the Linux operating system offers a Swiss Army knife built directly into its kernel. We are talking about the tc (Traffic Control) command, part of the iproute2 package, which manages the flow of packets across network interfaces. Combined with the Netem (Network Emulator) module, tc allows engineers to inject temporal delays, corrupt data, duplicate traffic, and drop packets surgically, simulating satellite connections, degraded 3G networks, or distant remote offices.
Understanding the Linux Kernel Queueing Architecture
To master traffic control, we must understand how the operating system handles data leaving the network card. The kernel uses queueing disciplines (qdisc) to organize the order in which network packets are transmitted or dropped. By default, most interfaces use a simple FIFO (First-In, First-Out) queue, where the first packet to arrive is the first one sent, without any prioritization or intentional speed limitation.
When we apply a bandwidth limiting or packet loss rule, we intercept this default queue and replace it with a programmable structure. Netem acts as a special qdisc that can be attached directly to the network interface or integrated into more complex structures, such as HTB (Hierarchical Token Bucket). In practice, HTB works as an intelligent token distributor, where each token grants permission to transmit a specific amount of bytes, allowing engineers to slice total bandwidth into restricted chunks for each application.
Preparing the Test Scenario on the Loopback Interface
Before applying any traffic modification to a physical network interface, which could cut off your remote SSH access to the machine, it is highly recommended to use the loopback interface (lo). This virtual interface represents the computer talking to itself, completely isolating experiments and ensuring a totally secure environment for stress testing and command validation.
To verify the current state of the loopback interface and confirm that no restrictive rules are active, we use the ip route utility or list the configured disciplines. In practice, this means we can test web servers, local databases, and API clients simulating high-latency international connections without needing to unplug the computer's physical network cable.
Applying Packet Loss and Simulated Delays with Netem
Let us move to the first practical engineering scenario: simulating an unstable mobile internet connection that randomly drops ten percent of sent packets and adds one hundred milliseconds of delay with jitter. To perform this procedure safely on your development machine, follow the sequence below using the Linux terminal with administrative privileges.
- Open the terminal and make sure to execute commands with superuser privileges to interact directly with the system kernel.
- Inspect the chosen network interface, such as the virtual loopback interface, to ensure it is active and responding correctly:
ip link show lo - Apply the Netem rule to the loopback interface to inject ten percent packet loss and one hundred milliseconds of base latency:
sudo tc qdisc add dev lo root netem loss 10% delay 100ms 20ms - Immediately validate if the rule was applied correctly by listing the active qdiscs on the interface:
sudo tc qdisc show dev lo - Test the new latency by sending diagnostic packets to the local address:
ping -c 5 127.0.0.1
With this simple change, monitoring tools and applications relying on continuous connections will start experiencing timeouts and retries. This behavior is essential to observe how client code handles partial network failures.
Limiting Bandwidth with Combined HTB and Netem
The netem command alone is excellent for delays and losses, but it does not restrict maximum transmission speed by itself. To limit bandwidth, for example, to exactly one megabit per second, we must create an HTB root and hang netem beneath it. This combination allows us to restrict speed and corrupt packets simultaneously, simulating a congested, low-capacity satellite link.
The command structure requires creating a root HTB class that controls the maximum outbound rate (rate 1mbit) and then adding a netem leaf subordinate to that class. In practice, any HTTP request or file transfer executed through this interface will now be tightly throttled by the kernel, allowing developers to observe buffer bottlenecks and memory overflows in real time.
Cleaning Up Rules and Restoring Original Network State
A common mistake when using the tc subsystem is forgetting to remove simulation rules after testing finishes. Because configurations persist in the network interface memory until the system reboots or the qdisc is explicitly cleared, future applications on the same machine will continue experiencing packet loss and unexplained sluggishness.
To revert all changes and restore the native high-speed behavior of the loopback interface or any physical card, we use the general cleanup command. In practice, executing this command instantly removes any custom queueing discipline, returning total traffic control to the default Linux kernel without requiring a computer reboot.
Final Considerations on Network Resilience Testing
Simulating adverse network scenarios locally using the Linux tc subsystem transforms how we architect distributed applications. Instead of discovering timeout failures and state corruption only when software hits production, engineers gain the ability to audit code behavior under extreme pressure directly on their development machine. Mastering these tools elevates system robustness and ensures consistent user experiences, regardless of connected infrastructure quality.