Skip to content

Instantly share code, notes, and snippets.

@aont
Last active July 16, 2025 15:18
Show Gist options
  • Select an option

  • Save aont/7c201a2ec8e317080367259d68277147 to your computer and use it in GitHub Desktop.

Select an option

Save aont/7c201a2ec8e317080367259d68277147 to your computer and use it in GitHub Desktop.

netns ipvlan L3 NAT

This Bash script sets up and tears down a network namespace using ipvlan (L3 mode) and NAT on a Linux system.

It has two main commands:

setup

  • Creates a new network namespace (a separate network environment).
  • Adds two ipvlan interfaces (host side and namespace side).
  • Assigns IP addresses and routing inside the namespace.
  • Sets up DNS for the namespace.
  • Enables IP forwarding and configures NAT using iptables so the namespace can access the internet.
  • Tests the internet connection with ping.

down

  • Deletes the ipvlan interfaces.
  • Removes the namespace and DNS config.
  • Clears the NAT rules.
  • Optionally resets system settings like IP forwarding.

🧠 Use Case

You can use this script to:

  • Create an isolated network environment for testing.
  • Simulate multiple networked hosts on one machine.
  • Experiment with network namespaces and ipvlan.

It is useful for Linux users or developers working on container networking, testing environments, or studying network configuration.

#!/bin/bash
set -euo pipefail
#============== Configurable Parameters =================================
NETNS=demo-ns # Name of the network namespace to create
SUBNET=192.168.100.0/24
GW_IP=192.168.100.1 # Default gateway visible to the netns
NS_IP=192.168.100.2 # IP address assigned inside the netns
PHYS_IF=eth0 # Physical interface connected to the internet
IPVLAN_HOST=ipvlan-host
IPVLAN_NS=ipvlan-ns
#=======================================================================
HOST_GW=$(ip route | awk '/^default/ && /dev '"${PHYS_IF}"'/ {print $3}')
############################################################
# Subcommand: setup
# Creates netns, configures ipvlan L3, sets NAT, and verifies connectivity
############################################################
setup() {
echo "[0] Create resolv.conf for DNS resolution"
mkdir -p /etc/netns/${NETNS}
echo "nameserver ${HOST_GW}" > "/etc/netns/${NETNS}/resolv.conf"
echo "[1] Create network namespace"
ip netns add "${NETNS}"
echo "[2] Create host-side ipvlan (L3 mode)"
ip link add "${IPVLAN_HOST}" link "${PHYS_IF}" type ipvlan mode l3
ip addr add "${GW_IP}/${SUBNET#*/}" dev "${IPVLAN_HOST}"
ip link set "${IPVLAN_HOST}" up
echo "[3] Create netns-side ipvlan and move it to the namespace"
ip link add "${IPVLAN_NS}" link "${PHYS_IF}" type ipvlan mode l3
ip link set "${IPVLAN_NS}" netns "${NETNS}"
echo "[4] Configure IP and default route inside netns"
ip netns exec "${NETNS}" bash -c "
ip addr add ${NS_IP}/${SUBNET#*/} dev ${IPVLAN_NS}
ip link set ${IPVLAN_NS} up
ip route add default via ${GW_IP}
"
echo "[5] Enable IPv4 forwarding and adjust rp_filter"
sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv4.conf.all.rp_filter=0
sysctl -w net.ipv4.conf.${PHYS_IF}.rp_filter=0
echo "[6] Set up NAT (using iptables-nft)"
iptables -t nat -C POSTROUTING -s "${SUBNET}" -o "${PHYS_IF}" -j MASQUERADE 2>/dev/null \
|| iptables -t nat -A POSTROUTING -s "${SUBNET}" -o "${PHYS_IF}" -j MASQUERADE
echo "[7] Test connectivity from netns (ping)"
ip netns exec "${NETNS}" ping -c 3 www.google.com
echo "=== setup complete ==="
}
############################################################
# Subcommand: down
# Cleans up all resources created by setup
############################################################
down() {
echo "[a] Kill ping processes if any (dummy step for idempotency)"
echo "[b] Remove NAT settings"
if iptables -t nat -C POSTROUTING -s "${SUBNET}" -o "${PHYS_IF}" -j MASQUERADE 2>/dev/null; then
iptables -t nat -D POSTROUTING -s "${SUBNET}" -o "${PHYS_IF}" -j MASQUERADE
fi
echo "[c] Delete host-side ipvlan"
ip link del "${IPVLAN_HOST}" 2>/dev/null || true
echo "[d] Delete the netns (ipvlan inside it is also removed)"
ip netns delete "${NETNS}" 2>/dev/null || true
echo "[e] Remove resolv.conf directory for the namespace"
rm -rf "/etc/netns/${NETNS}"
echo "[f] Optionally reset sysctl settings (skip if shared)"
sysctl -w net.ipv4.ip_forward=0
sysctl -w net.ipv4.conf.all.rp_filter=1
sysctl -w net.ipv4.conf.${PHYS_IF}.rp_filter=1
echo "=== down complete ==="
}
############################################################
# Entrypoint
############################################################
usage() {
cat <<EOF
Usage: $(basename "$0") {setup|down}
setup : Set up network namespace with ipvlan and NAT
down : Tear down all the resources and restore settings
EOF
}
main() {
[[ $# -eq 1 ]] || { usage; exit 1; }
case "$1" in
setup) setup ;;
down) down ;;
*) usage; exit 1 ;;
esac
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment