While testing a network scenario that involved verifying multiple BGP sessions and simulating realistic client traffic to a network edge device, I needed several clients each with a unique IP to validate session scalability, routing policies, and traffic flow behavior.
The problem?
In the provided testbed, I had only one physical client machine sitting behind the edge. Testing with a single client meant I couldn’t truly replicate how the network would behave under real-world, multi-client conditions.
Sure, there are advanced tools like Spirent and TRex that can emulate thousands of clients and generate high-volume traffic. But due to resource and licensing constraints, I couldn’t access those tools for this setup.
While researching alternatives, I stumbled upon Linux’s built-in networking capabilities, specifically network namespaces and MACVLAN interfaces. They turned out to be a lightweight and effective way to simulate multiple clients on a single host without requiring extra hardware or commercial traffic generators.
Note: This post is just knowledge sharing based on my personal experience. The concepts aren’t new, but I hope this helps someone facing similar limitations in their network testbeds.
🧠 Understanding the Building Blocks
1️⃣ Network Namespaces
A network namespace provides an isolated copy of the Linux networking stack. Each namespace has its own:
- Interfaces
- IP routing tables
- Firewall rules
- Network configuration
Processes running in one namespace are isolated from others. This makes namespaces ideal for simulating separate client machines on the same host.
2️⃣ MACVLAN Interfaces
A MACVLAN is a virtual interface that allows multiple unique MAC and IP addresses to exist on a single physical NIC. Each MACVLAN interface behaves like an independent host on the network, making it visible to your router or edge device as a separate client.
🎯 The Goal
We’ll use these tools to:
- Create multiple network namespaces (simulating clients)
- Attach a MACVLAN interface to each namespace
- Assign unique IPs and MACs to each interface
- Test connectivity, traffic flows—all from a single physical machine.
⚙️ Step-by-Step Setup on Ubuntu
Let’s assume:
- Physical NIC:
eth0
- Network:
192.168.100.0/24
- Gateway:
192.168.100.1
Step 1: Create 5 network namespaces
sudo ip netns add ns1
sudo ip netns add ns2
sudo ip netns add ns3
sudo ip netns add ns4
sudo ip netns add ns5
Step 2: Create MACVLAN interfaces and assign them to namespaces
sudo ip link add macvlan1 link eth0 type macvlan mode bridge
sudo ip link set macvlan1 netns ns1
sudo ip link add macvlan2 link eth0 type macvlan mode bridge
sudo ip link set macvlan2 netns ns2
sudo ip link add macvlan3 link eth0 type macvlan mode bridge
sudo ip link set macvlan3 netns ns3
sudo ip link add macvlan4 link eth0 type macvlan mode bridge
sudo ip link set macvlan4 netns ns4
sudo ip link add macvlan5 link eth0 type macvlan mode bridge
sudo ip link set macvlan5 netns ns5
Step 3: Bring interfaces up, assign IPs, and configure routes inside namespaces
# Namespace ns1
sudo ip netns exec ns1 ip link set dev macvlan1 up
sudo ip netns exec ns1 ip addr add 192.168.100.11/24 dev macvlan1
sudo ip netns exec ns1 ip route add default via 192.168.100.1
# Namespace ns2
sudo ip netns exec ns2 ip link set dev macvlan2 up
sudo ip netns exec ns2 ip addr add 192.168.100.12/24 dev macvlan2
sudo ip netns exec ns2 ip route add default via 192.168.100.1
# Namespace ns3
sudo ip netns exec ns3 ip link set dev macvlan3 up
sudo ip netns exec ns3 ip addr add 192.168.100.13/24 dev macvlan3
sudo ip netns exec ns3 ip route add default via 192.168.100.1
# Namespace ns4
sudo ip netns exec ns4 ip link set dev macvlan4 up
sudo ip netns exec ns4 ip addr add 192.168.100.14/24 dev macvlan4
sudo ip netns exec ns4 ip route add default via 192.168.100.1
# Namespace ns5
sudo ip netns exec ns5 ip link set dev macvlan5 up
sudo ip netns exec ns5 ip addr add 192.168.100.15/24 dev macvlan5
sudo ip netns exec ns5 ip route add default via 192.168.100.1
Step 4: Test connectivity
sudo ip netns exec ns1 ping -c 3 192.168.100.1
sudo ip netns exec ns2 ping -c 3 192.168.100.1
sudo ip netns exec ns3 ping -c 3 192.168.100.1
sudo ip netns exec ns4 ping -c 3 192.168.100.1
sudo ip netns exec ns5 ping -c 3 192.168.100.1
From the perspective of the edge device, you’ll see multiple unique clients, each with its own IP/MAC.
🖼️ Network Diagram
+-------------------------- Host Machine ---------------------------+
eth0 (Physical NIC)
|
+-------------+--------------------+
| | |
macvlan1 macvlan2 ... macvlan5(linked to eth0)
| | |
+----------+------+ +---+-------------+ +------+------------+
| Namespace ns1 | | Namespace ns2 | ... | Namespace ns5 |
|-----------------| |-----------------| |-------------------|
|IP:192.168.100.11| |IP:192.168.100.12| ... | IP:192.168.100.15 |
|MAC: unique | |MAC: unique | | MAC: unique |
+-----------------+ +-----------------+ +-------------------+
🧪 Example: BGP Configuration Inside a Namespace Using VRFs
After bringing up the MACVLAN interfaces and namespaces, I configured FRRouting (FRR) to run a BGP instance for each namespace using VRFs. Here's an example configuration for ns1:
!
router bgp 65001 vrf ns1
bgp router-id 192.168.100.11
neighbor 192.168.100.1 remote-as 65000
address-family ipv4 unicast
network 192.168.100.11/32
exit-address-family
!
Each VRF (tied to a namespace) was treated as an independent BGP instance. I replicated this configuration across all namespaces with unique IPs and ASNs as needed.
This setup allowed me to simulate hundreds of BGP peers, test session scalability, and validate policy behavior — all from a single host using just MACVLANs, network namespaces, and FRR.
✅ Benefits of This Approach
- Lightweight: No additional VMs or containers are needed to simulate multiple clients — just native Linux tools
- Realistic: Each simulated client gets its own unique IP and MAC address
- Efficient: Quick to set up, easy to tear down, and fully scriptable
- Cost-effective: Eliminates the need for commercial traffic generators or extra hardware
- Scalable: Easily expand to simulate dozens or hundreds of clients — even up to 1000+ namespaces, depending on your host's capacity.
Note: Each namespace and virtual interface consumes file descriptors (FDs).
If you're scaling beyond ~1024 namespaces, you may need to increase your system’s nofile (max open file descriptors) limit using ulimit -n.
I was able to simulate around 2000 clients on a single Ubuntu machine after increasing the limit.
🚀 Conclusion
With Linux network namespaces and MACVLAN, you can simulate multiple isolated network clients on a single physical machine — without relying on virtualization or commercial tools.
This method is ideal for testing routing protocols like BGP or OSPF, validating firewall or NAT behavior, and creating isolated setups for penetration testing or troubleshooting. It’s a scalable and cost-effective way to emulate realistic network scenarios using just native Linux tools.
This approach helped me complete my test scenario when commercial tools weren’t available. Hopefully, this knowledge-sharing post saves someone else time when faced with similar constraints.
Top comments (0)