Understanding and Implementing Linux Network Namespaces

Linux network namespaces are a fundamental kernel feature that enables network isolation, forming the backbone of modern containerization technologies like Docker and Kubernetes. Understanding network namespaces is essential for anyone working with containers, networking, or system administration. This guide provides comprehensive coverage of network namespaces, from basic concepts to advanced implementation patterns.

Introduction to Linux Namespaces

Namespaces are a Linux kernel feature that partitions kernel resources so that one set of processes sees one set of resources while another set of processes sees a different set. Linux provides several types of namespaces:

  • PID: Process ID isolation
  • NET: Network stack isolation
  • MNT: Mount point isolation
  • UTS: Hostname and domain name isolation
  • IPC: Inter-process communication isolation
  • USER: User and group ID isolation
  • CGROUP: Control group isolation

Network namespaces specifically isolate network resources, providing each namespace with its own network stack, including network interfaces, routing tables, firewall rules, and sockets.

Network Namespace Fundamentals

What Gets Isolated in Network Namespaces

Each network namespace contains:

  • Network interfaces: Physical or virtual NICs
  • IPv4 and IPv6 protocol stacks: Independent IP addressing
  • Routing tables: Separate routing decisions
  • Firewall rules: Independent iptables/nftables rules
  • Port numbers: Same port can be used in different namespaces
  • UNIX domain sockets: Network-type sockets
  • /proc/net directory: Per-namespace network information
  • /sys/class/net directory: Per-namespace network device info

Default Network Namespace

The root (default) network namespace contains all network resources when the system boots. All processes inherit this namespace unless explicitly moved to another.

Creating and Managing Network Namespaces

Basic Commands with ip netns

The ip command from the iproute2 package manages network namespaces.

Create a network namespace:

sudo ip netns add myns

List network namespaces:

sudo ip netns list

Delete a network namespace:

sudo ip netns delete myns

Execute command in namespace:

sudo ip netns exec myns <command>

For example:

# Run bash shell in namespace
sudo ip netns exec myns bash

## Check interfaces in namespace
sudo ip netns exec myns ip link show

## Check routing table
sudo ip netns exec myns ip route show

Understanding Namespace Persistence

Network namespaces created with ip netns are persisted as bind mounts in /var/run/netns/:

ls -l /var/run/netns/

This persistence allows namespaces to exist even when no processes are running in them.

Exploring a New Namespace

When you create a new network namespace, it starts empty:

## Create namespace
sudo ip netns add test

## Check interfaces (only loopback exists, and it's down)
sudo ip netns exec test ip link show

## Check routing
sudo ip netns exec test ip route show

## Check IP addresses
sudo ip netns exec test ip addr show

Output shows only the loopback interface in DOWN state:

1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

Enable the loopback interface:

sudo ip netns exec test ip link set lo up
sudo ip netns exec test ip addr show lo

Connecting Network Namespaces

Namespaces start isolated. To enable communication, we need to create connections.

Virtual Ethernet (veth) Pairs

veth pairs are virtual ethernet devices that act like a network cable—packets sent into one end come out the other. They’re the primary mechanism for connecting namespaces.

Create veth pair:

## Create pair named veth0 and veth1
sudo ip link add veth0 type veth peer name veth1

View the pair:

ip link show type veth

Move one end to namespace:

## Create namespace
sudo ip netns add ns1

## Move veth1 to ns1
sudo ip link set veth1 netns ns1

Now veth1 doesn’t appear in the default namespace:

ip link show veth1  # Not found
sudo ip netns exec ns1 ip link show veth1  # Found in ns1

Configure IP addresses and bring up:

## Configure veth0 in default namespace
sudo ip addr add 10.0.0.1/24 dev veth0
sudo ip link set veth0 up

## Configure veth1 in ns1
sudo ip netns exec ns1 ip addr add 10.0.0.2/24 dev veth1
sudo ip netns exec ns1 ip link set veth1 up

Test connectivity:

ping -c 3 10.0.0.2
sudo ip netns exec ns1 ping -c 3 10.0.0.1

Connecting Two Namespaces

Create two isolated namespaces and connect them:

## Create namespaces
sudo ip netns add red
sudo ip netns add blue

## Create veth pair
sudo ip link add veth-red type veth peer name veth-blue

## Move interfaces to namespaces
sudo ip link set veth-red netns red
sudo ip link set veth-blue netns blue

## Configure red namespace
sudo ip netns exec red ip addr add 192.168.1.1/24 dev veth-red
sudo ip netns exec red ip link set veth-red up
sudo ip netns exec red ip link set lo up

## Configure blue namespace
sudo ip netns exec blue ip addr add 192.168.1.2/24 dev veth-blue
sudo ip netns exec blue ip link set veth-blue up
sudo ip netns exec blue ip link set lo up

## Test connectivity
sudo ip netns exec red ping -c 3 192.168.1.2
sudo ip netns exec blue ping -c 3 192.168.1.1

Bridge Networks and Namespaces

For connecting multiple namespaces, bridges are more scalable than point-to-point veth pairs.

Creating a Bridge

## Create bridge
sudo ip link add br0 type bridge
sudo ip link set br0 up
sudo ip addr add 10.0.0.1/24 dev br0

Connecting Multiple Namespaces to Bridge

## Create three namespaces
for i in 1 2 3; do
    sudo ip netns add ns$i
done

## Create veth pairs and connect to bridge
for i in 1 2 3; do
    # Create veth pair
    sudo ip link add veth$i type veth peer name veth-br$i
    
    # Connect one end to bridge
    sudo ip link set veth-br$i master br0
    sudo ip link set veth-br$i up
    
    # Move other end to namespace
    sudo ip link set veth$i netns ns$i
    
    # Configure in namespace
    sudo ip netns exec ns$i ip addr add 10.0.0.$((i+1))/24 dev veth$i
    sudo ip netns exec ns$i ip link set veth$i up
    sudo ip netns exec ns$i ip link set lo up
done

Test connectivity between namespaces:

sudo ip netns exec ns1 ping -c 2 10.0.0.2
sudo ip netns exec ns1 ping -c 2 10.0.0.3
sudo ip netns exec ns2 ping -c 2 10.0.0.3

All namespaces can now communicate through the bridge.

Providing Internet Access to Namespaces

Namespaces isolated from the host need routing and NAT to access the internet.

Setup Internet Gateway

Assuming eth0 is your internet-connected interface:

## Enable IP forwarding
sudo sysctl -w net.ipv4.ip_forward=1

## Make permanent
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf

## Configure NAT (iptables)
sudo iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 -j MASQUERADE
sudo iptables -A FORWARD -i br0 -o eth0 -j ACCEPT
sudo iptables -A FORWARD -i eth0 -o br0 -m state --state RELATED,ESTABLISHED -j ACCEPT

Configure Default Route in Namespace

## Add default route via bridge
sudo ip netns exec ns1 ip route add default via 10.0.0.1

## Configure DNS
sudo mkdir -p /etc/netns/ns1
echo "nameserver 8.8.8.8" | sudo tee /etc/netns/ns1/resolv.conf

## Test internet connectivity
sudo ip netns exec ns1 ping -c 3 8.8.8.8
sudo ip netns exec ns1 ping -c 3 google.com

Advanced Namespace Operations

Running Services in Namespaces

Start a web server in an isolated namespace:

## Create and configure namespace
sudo ip netns add webserver
sudo ip link add veth-web type veth peer name veth-web-br
sudo ip link set veth-web-br master br0 up
sudo ip link set veth-web netns webserver
sudo ip netns exec webserver ip addr add 10.0.0.10/24 dev veth-web
sudo ip netns exec webserver ip link set veth-web up
sudo ip netns exec webserver ip link set lo up
sudo ip netns exec webserver ip route add default via 10.0.0.1

## Run Python HTTP server in namespace
sudo ip netns exec webserver python3 -m http.server 8080 &

## Access from another namespace
sudo ip netns exec ns1 curl http://10.0.0.10:8080

Port Forwarding to Namespaces

Forward traffic from host port to namespace service:

## Forward host port 8080 to namespace port 8080
sudo iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 10.0.0.10:8080
sudo iptables -A FORWARD -p tcp -d 10.0.0.10 --dport 8080 -j ACCEPT

## Now accessible from external network
curl http://<host-ip>:8080

Network Namespace with VLAN

Create namespace connected to VLAN:

## Create VLAN interface
sudo ip link add link eth0 name eth0.100 type vlan id 100
sudo ip link set eth0.100 up

## Create namespace
sudo ip netns add vlan-ns

## Create and configure veth pair
sudo ip link add veth-vlan type veth peer name veth-vlan-br
sudo ip link set veth-vlan netns vlan-ns
sudo ip link set veth-vlan-br master br0 up

## Configure in namespace
sudo ip netns exec vlan-ns ip addr add 10.100.0.2/24 dev veth-vlan
sudo ip netns exec vlan-ns ip link set veth-vlan up
sudo ip netns exec vlan-ns ip link set lo up

Container Networking Patterns

Docker-Style Container Networking

Docker creates network namespaces for containers and connects them via bridges.

Simulate Docker network model:

## Create docker-like bridge
sudo ip link add docker0 type bridge
sudo ip addr add 172.17.0.1/16 dev docker0
sudo ip link set docker0 up

## Create container namespace
sudo ip netns add container1

## Connect to bridge
sudo ip link add veth0 type veth peer name veth0-br
sudo ip link set veth0-br master docker0 up
sudo ip link set veth0 netns container1

## Configure container
sudo ip netns exec container1 ip addr add 172.17.0.2/16 dev veth0
sudo ip netns exec container1 ip link set veth0 up
sudo ip netns exec container1 ip link set lo up
sudo ip netns exec container1 ip route add default via 172.17.0.1

## Enable NAT
sudo iptables -t nat -A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE

Multiple Isolated Networks

Create multiple isolated networks, each with its own bridge:

## Network 1: Frontend
sudo ip link add br-frontend type bridge
sudo ip addr add 10.1.0.1/24 dev br-frontend
sudo ip link set br-frontend up

## Network 2: Backend
sudo ip link add br-backend type bridge
sudo ip addr add 10.2.0.1/24 dev br-backend
sudo ip link set br-backend up

## Create container connected to both networks
sudo ip netns add app-container

## Connect to frontend
sudo ip link add veth-front type veth peer name veth-front-br
sudo ip link set veth-front-br master br-frontend up
sudo ip link set veth-front netns app-container
sudo ip netns exec app-container ip addr add 10.1.0.2/24 dev veth-front
sudo ip netns exec app-container ip link set veth-front up

## Connect to backend
sudo ip link add veth-back type veth peer name veth-back-br
sudo ip link set veth-back-br master br-backend up
sudo ip link set veth-back netns app-container
sudo ip netns exec app-container ip addr add 10.2.0.2/24 dev veth-back
sudo ip netns exec app-container ip link set veth-back up

## Now app-container has interfaces on both networks
sudo ip netns exec app-container ip addr show

Debugging Network Namespaces

Inspecting Namespace Configuration

List all interfaces:

sudo ip netns exec myns ip link show

Show IP addresses:

sudo ip netns exec myns ip addr show

Show routing table:

sudo ip netns exec myns ip route show

Show ARP cache:

sudo ip netns exec myns ip neigh show

Show firewall rules:

sudo ip netns exec myns iptables -L -n -v
sudo ip netns exec myns iptables -t nat -L -n -v

Testing Connectivity

Ping test:

sudo ip netns exec myns ping -c 3 10.0.0.1

Trace route:

sudo ip netns exec myns traceroute 8.8.8.8

Check listening ports:

sudo ip netns exec myns netstat -tulpn
## or
sudo ip netns exec myns ss -tulpn

DNS resolution:

sudo ip netns exec myns nslookup google.com
sudo ip netns exec myns dig google.com

TCP connectivity:

## Test with netcat
sudo ip netns exec myns nc -zv 10.0.0.1 80

Traffic Capture

Capture packets in namespace:

## Install tcpdump in namespace
sudo ip netns exec myns tcpdump -i veth0 -n

## Save to file
sudo ip netns exec myns tcpdump -i veth0 -w capture.pcap

## Analyze with wireshark
wireshark capture.pcap

Security Considerations

Namespace Isolation Limits

Network namespaces provide network-level isolation but:

  • Share kernel: All namespaces share the same kernel
  • Resource limits: No automatic resource limits (use cgroups)
  • Root privileges: Root in namespace can affect host
  • Side-channel attacks: Possible through shared kernel resources

Best Practices

  1. Combine with other namespaces: Use PID, mount, and user namespaces together
  2. Use user namespaces: Map root in namespace to non-root on host
  3. Apply resource limits: Use cgroups to limit CPU, memory, network bandwidth
  4. Firewall rules: Apply strict iptables rules per namespace
  5. Limit capabilities: Drop unnecessary Linux capabilities
  6. SELinux/AppArmor: Additional MAC layer protection
  7. Network policies: Implement network segmentation and policies
  8. Monitor activity: Log and monitor namespace network activity

Practical Automation Scripts

Script to Create Isolated Container

#!/bin/bash

NAMESPACE=$1
IP_ADDR=$2

if [ -z "$NAMESPACE" ] || [ -z "$IP_ADDR" ]; then
    echo "Usage: $0 <namespace> <ip_address>"
    exit 1
fi

## Create namespace
ip netns add "$NAMESPACE"

## Create veth pair
VETH="${NAMESPACE}-veth"
VETH_BR="${NAMESPACE}-veth-br"
ip link add "$VETH" type veth peer name "$VETH_BR"

## Attach to bridge (assume br0 exists)
ip link set "$VETH_BR" master br0
ip link set "$VETH_BR" up

## Move to namespace
ip link set "$VETH" netns "$NAMESPACE"

## Configure in namespace
ip netns exec "$NAMESPACE" ip addr add "$IP_ADDR/24" dev "$VETH"
ip netns exec "$NAMESPACE" ip link set "$VETH" up
ip netns exec "$NAMESPACE" ip link set lo up
ip netns exec "$NAMESPACE" ip route add default via 10.0.0.1

echo "Namespace $NAMESPACE created with IP $IP_ADDR"

Script to Clean Up Namespace

#!/bin/bash

NAMESPACE=$1

if [ -z "$NAMESPACE" ]; then
    echo "Usage: $0 <namespace>"
    exit 1
fi

## Delete namespace (automatically removes interfaces in it)
ip netns delete "$NAMESPACE"

## Clean up bridge interface if exists
VETH_BR="${NAMESPACE}-veth-br"
if ip link show "$VETH_BR" &>/dev/null; then
    ip link delete "$VETH_BR"
fi

echo "Namespace $NAMESPACE deleted"

Performance Considerations

Network Namespace Overhead

Network namespaces have minimal performance impact:

  • Context switching: Slight overhead when switching between namespaces
  • veth throughput: Nearly native performance (90-95% of physical interface)
  • Bridge overhead: Minimal impact for most workloads
  • Memory usage: ~1MB per namespace for network stack

Optimization Tips

  1. Use veth offloading:
ethtool -K veth0 tx off rx off
  1. Increase queue length:
ip link set veth0 txqueuelen 10000
  1. Enable bridge fast path:
sysctl -w net.bridge.bridge-nf-call-iptables=0
sysctl -w net.bridge.bridge-nf-call-ip6tables=0
  1. Use jumbo frames if network supports:
ip link set veth0 mtu 9000
  1. Tune TCP settings per namespace:
ip netns exec myns sysctl -w net.ipv4.tcp_congestion_control=bbr
ip netns exec myns sysctl -w net.core.rmem_max=134217728
ip netns exec myns sysctl -w net.core.wmem_max=134217728

Integration with Container Runtimes

How Docker Uses Network Namespaces

Docker automatically:

  1. Creates network namespace per container
  2. Creates veth pair
  3. Connects one end to docker0 bridge
  4. Moves other end into container namespace
  5. Configures IP address and routing
  6. Sets up NAT for outbound traffic
  7. Configures DNS

View Docker network namespaces:

## Find container PID
docker inspect -f '{{.State.Pid}}' <container>

## Access its network namespace
sudo nsenter -t <PID> -n ip addr

How Kubernetes Uses Network Namespaces

Kubernetes CNI (Container Network Interface) plugins:

  1. Create network namespace for pod
  2. Configure networking per CNI plugin (Calico, Flannel, etc.)
  3. Assign IP from pod CIDR
  4. Set up routes for pod-to-pod communication
  5. Implement network policies

List pod network namespaces:

## On Kubernetes node
sudo ip netns list | grep cni

Conclusion

Linux network namespaces provide powerful network isolation capabilities that form the foundation of modern container technologies. Understanding how to create, connect, and manage network namespaces is essential for working with containers, debugging networking issues, and implementing custom network topologies.

From simple point-to-point connections using veth pairs to complex multi-network architectures with bridges and NAT, network namespaces offer flexibility and isolation without significant performance overhead. Combined with other namespace types, cgroups, and security features, they enable secure, isolated environments for running applications.

Whether you’re troubleshooting Docker networking, implementing custom container solutions, or simply exploring Linux networking capabilities, mastering network namespaces opens up new possibilities for network architecture and isolation strategies.


References

Thank you for reading! If you have any feedback or comments, please send them to [email protected].