ip netns 是 Linux 的 Network Namespace 管理工具,属于 iproute2 包。用于创建、列出、删除和操作 Network Namespaces。
ip netns 详解
1. 基本概念
ip netns 用于管理 Network Namespaces,让每个 Namespace 拥有独立的网络栈(接口、路由、防火墙规则等)。
2. 基本命令
bash
# 查看所有 Network Namespaces
ip netns list
# 创建新的 Network Namespace
ip netns add <name>
# 删除 Network Namespace
ip netns delete <name>
# 在指定的 Network Namespace 中执行命令
ip n
3. 实际使用示例
示例 1:创建和查看 Network Namespace
完整图解:veth pair 连接两个 Network Namespaces
初始状态:创建两个 Network Namespaces
bash
┌─────────────────────────────────────────────────────────┐
│ Linux 主机 │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ red Namespace│ │blue Namespace│ │
│ │ │ │ │ │
│ │ (空的) │ │ (空的) │ │
│ │ │ │ │ │
│ │ 只有 lo │ │ 只有 lo │ │
│ └──────────────┘ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘

bash
# 创建两个 Network Namespaces
sudo ip netns add red
sudo ip netns add blue
# 查看所有 Network Namespaces
ip netns list
# 输出:
# red
# blue
# 查看每个 Namespace 的网络接口
sudo ip netns exec red ip addr show
# 输出:只有 lo(回环接口)
sudo ip netns exec blue ip addr show
# 输出:只有 lo(回环接口)
ip addr show 输出详解

整体含义
这是 lo(loopback,回环)接口的信息,状态为 DOWN(未启动)。
逐行解析
bash
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
- 1::接口索引号
- lo::接口名称(loopback)
- <LOOPBACK>:接口类型(回环)
- mtu 65536:最大传输单元(字节)
- qdisc noop:队列规则(noop = 无操作,不排队)
- state DOWN:接口状态(DOWN = 关闭,UP = 启动)
- group default:接口组
- qlen 1000:队列长度
bash
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
- link/loopback:链路类型(回环)
- 00:00:00:00:00:00:MAC 地址(回环接口固定为全 0)
- brd 00:00:00:00:00:00:广播地址(回环接口也是全 0)
关键点
- state DOWN:接口未启动,无法通信
- 没有 IP 地址:输出中没有 inet 行,说明未配置 IP
- 这是新创建的 Network Namespace:只有默认的 lo 接口
bash
# 创建 veth pair(虚拟以太网对)
sudo ip link add veth-red type veth peer name veth-blue
┌─────────────────────────────────────────────────────────┐
│ Linux 主机 │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ red Namespace│ │blue Namespace│ │
│ │ │ │ │ │
│ │ 只有 lo │ │ 只有 lo │ │
│ └──────────────┘ └──────────────┘ │
│ │
│ 主机上创建了 veth pair: │
│ │
│ veth-red <===========> veth-blue │
│ (一端) 虚拟网线 (另一端) │
│ │
│ 注意:此时接口还在主机上,不在 Namespace 中! │
└─────────────────────────────────────────────────────────┘
# 将接口放入各自的 Namespace
sudo ip link set veth-red netns red
sudo ip link set veth-blue netns blue
┌─────────────────────────────────────────────────────────┐
│ Linux 主机 │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ red Namespace│ │blue Namespace│ │
│ │ │ │ │ │
│ │ lo │ │ lo │ │
│ │ veth-red │ │ veth-blue │ │
│ │ (DOWN) │ │ (DOWN) │ │
│ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │
│ └──────── veth pair ───────────┘ │
│ (虚拟网线连接) │
│ │
│ 注意:接口已移动到各自的 Namespace,但状态是 DOWN │
└─────────────────────────────────────────────────────────┘
# 在 red Namespace 中配置 IP
sudo ip netns exec red ip addr add 10.0.0.1/24 dev veth-red
sudo ip netns exec red ip link set veth-red up
┌─────────────────────────────────────────────────────────┐
│ Linux 主机 │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ red Namespace│ │blue Namespace│ │
│ │ │ │ │ │
│ │ lo │ │ lo │ │
│ │ veth-red │ │ veth-blue │ │
│ │ 10.0.0.1 │ │ (DOWN) │ │
│ │ (UP) ✓ │ │ (未配置) │ │
│ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │
│ └──────── veth pair ───────────┘ │
│ (虚拟网线连接) │
│ │
│ red 端已配置 IP 并启动,blue 端还未配置 │
└─────────────────────────────────────────────────────────┘
# 在 blue Namespace 中配置 IP
sudo ip netns exec blue ip addr add 10.0.0.2/24 dev veth-blue
sudo ip netns exec blue ip link set veth-blue up
# 测试连通性
sudo ip netns exec red ping 10.0.0.2
┌─────────────────────────────────────────────────────────┐
│ Linux 主机 │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ red Namespace│ │blue Namespace│ │
│ │ │ │ │ │
│ │ ping 命令 │ │ │ │
│ │ 发送数据包 │ │ │ │
│ │ │ │ │ │
│ │ veth-red │ │ veth-blue │ │
│ │ 10.0.0.1 │ │ 10.0.0.2 │ │
│ │ (UP) ✓ │ │ (UP) ✓ │ │
│ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │
│ │ ICMP Echo Request │ │
│ │ (ping 10.0.0.2) │ │
│ └──────────────>───────────────┘ │
│ │ │
│ │ ICMP Echo Reply │
│ │ (pong) │
│ <──────────────────┘ │
│ │
│ 数据包通过 veth pair 传输 │
└─────────────────────────────────────────────────────────┘
详细执行流程
步骤 1:命令执行位置
┌─────────────────────────────────────────────────────────┐
│ Linux 主机 │
│ │
│ 主机 Shell: │
│ ┌──────────────────────────────────────────────┐ │
│ │ $ sudo ip netns exec red ping 10.0.0.2 │ │
│ │ │ │
│ │ 这个命令在主机上执行,但会: │ │
│ │ 1. 切换到 red Network Namespace │ │
│ │ 2. 在 red Namespace 中启动 ping 进程 │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ red Namespace│ │blue Namespace│ │
│ │ │ │ │ │
│ │ ping 进程 │ │ │ │
│ │ (PID: 1234) │ │ │ │
│ │ │ │ │ │
│ │ veth-red │ │ veth-blue │ │
│ │ 10.0.0.1 │ │ 10.0.0.2 │ │
│ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │
│ └──────── veth pair ───────────┘ │
└─────────────────────────────────────────────────────────┘
步骤 2:ping 进程的网络视图
在 red Namespace 中,ping 进程看到的网络环境:
┌─────────────────────────────────────────────────────────┐
│ red Network Namespace(ping 进程的视角) │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ ping 进程 (PID: 1234) │ │
│ │ │ │
│ │ 执行:ping 10.0.0.2 │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ ping 进程看到的网络接口: │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ 1. lo (127.0.0.1) │ │
│ │ 2. veth-red (10.0.0.1) │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ └─────────────────────────────────────────────────────────┘
步骤 3:ping 创建数据包的过程
┌─────────────────────────────────────────────────────────┐
│ red Network Namespace │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ ping 进程 │ │
│ │ │ │
│ │ 1. 解析目标地址:10.0.0.2 │ │
│ │ 2. 查找路由表: │ │
│ │ $ ip route show │ │
│ │ 10.0.0.0/24 dev veth-red scope link │ │
│ │ │ │
│ │ 3. 确定发送接口:veth-red │ │
│ │ 4. 确定源 IP:10.0.0.1(veth-red 的 IP) │ │
│ │ │ │
│ │ 5. 创建 ICMP Echo Request 数据包: │ │
│ │ ┌──────────────────────────────────┐ │ │
│ │ │ Layer 2 (Ethernet): │ │ │
│ │ │ Src MAC: veth-red 的 MAC │ │ │
│ │ │ Dst MAC: veth-blue 的 MAC │ │ │
│ │ │ │ │ │
│ │ │ Layer 3 (IP): │ │ │
│ │ │ Src IP: 10.0.0.1 │ │ │
│ │ │ Dst IP: 10.0.0.2 │ │ │
│ │ │ │ │ │
│ │ │ Layer 4 (ICMP): │ │ │
│ │ │ Type: Echo Request │ │ │
│ │ │ Data: ping payload │ │ │
│ │ └──────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ 数据包发送到网络栈 │
│ ↓ │
│ ┌──────────────────────────────────────────────┐ │
│ │ Linux 网络栈(red Namespace) │ │
│ │ │ │
│ │ 1. ICMP 层:封装 ICMP 数据 │ │
│ │ 2. IP 层:添加 IP 头(10.0.0.1 -> 10.0.0.2)│ │
│ │ 3. 路由:查找出口接口(veth-red) │ │
│ │ 4. ARP:查找目标 MAC(如果需要) │ │
│ │ 5. 链路层:通过 veth-red 发送 │ │
│ └──────────────────────────────────────────────┘ │
│ ↓ │
│ ┌──────────────────────────────────────────────┐ │
│ │ veth-red (10.0.0.1) │ │
│ │ 物理发送数据包 │ │
│ └──────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
步骤 4:数据包通过 veth pair 传输
┌─────────────────────────────────────────────────────────┐
│ red Network Namespace │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ veth-red (10.0.0.1) │ │
│ │ │ │
│ │ 数据包从这里发送: │ │
│ │ ┌──────────────────────────────────────┐ │ │
│ │ │ Src: 10.0.0.1 │ │ │
│ │ │ Dst: 10.0.0.2 │ │ │
│ │ │ ICMP Echo Request │ │ │
│ │ └──────────────────────────────────────┘ │ │
│ └──────────────┬───────────────────────────────┘ │
│ │ │
│ │ 数据包通过 veth pair │
│ │ (内核直接转发,不经过主机网络栈) │
│ ↓ │
└─────────────────┼───────────────────────────────────────┘
│
│ veth pair(虚拟网线)
│
┌─────────────────┼───────────────────────────────────────┐
│ ↓ │
│ ┌──────────────┴───────────────────────────────┐ │
│ │ veth-blue (10.0.0.2) │ │
│ │ │ │
│ │ 数据包在这里接收: │ │
│ │ ┌──────────────────────────────────────┐ │ │
│ │ │ Src: 10.0.0.1 │ │ │
│ │ │ Dst: 10.0.0.2 │ │ │
│ │ │ ICMP Echo Request │ │ │
│ │ └──────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ blue Network Namespace │
└─────────────────────────────────────────────────────────┘
要点:
数据包从 veth-red 发送
通过 veth pair 立即到达 veth-blue
不经过主机网络栈,是内核直接转发
步骤 5:blue Namespace 接收并处理
┌─────────────────────────────────────────────────────────┐
│ blue Network Namespace │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ veth-blue (10.0.0.2) │ │
│ │ 接收数据包 │ │
│ └──────────────┬───────────────────────────────┘ │
│ ↓ │
│ ┌──────────────────────────────────────────────┐ │
│ │ Linux 网络栈(blue Namespace) │ │
│ │ │ │
│ │ 1. 链路层:veth-blue 接收 │ │
│ │ 2. IP 层:检查目标 IP(10.0.0.2) │ │
│ │ 3. ICMP 层:识别为 ICMP Echo Request │ │
│ │ 4. 内核 ICMP 处理程序: │ │
│ │ - 创建 ICMP Echo Reply │ │
│ │ - 交换源/目标 IP │ │
│ │ - 通过 veth-blue 发送回复 │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ 注意:blue Namespace 中没有运行 ping 进程! │
│ ICMP Echo Reply 是由内核自动生成的! │
└─────────────────────────────────────────────────────────┘
重要:
blue Namespace 中没有 ping 进程
ICMP Echo Reply 由内核 ICMP 处理程序自动生成
不需要应用程序监听
步骤 6:回复数据包返回
┌─────────────────────────────────────────────────────────┐
│ blue Network Namespace │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ veth-blue (10.0.0.2) │ │
│ │ │ │
│ │ 内核发送 ICMP Echo Reply: │ │
│ │ ┌──────────────────────────────────────┐ │ │
│ │ │ Src: 10.0.0.2 │ │ │
│ │ │ Dst: 10.0.0.1 │ │ │
│ │ │ ICMP Echo Reply │ │ │
│ │ └──────────────────────────────────────┘ │ │
│ └──────────────┬───────────────────────────────┘ │
│ │ │
│ │ 数据包通过 veth pair │
│ ↓ │
└─────────────────┼───────────────────────────────────────┘
│
│ veth pair(虚拟网线)
│
┌─────────────────┼───────────────────────────────────────┐
│ ↓ │
│ ┌──────────────┴───────────────────────────────┐ │
│ │ veth-red (10.0.0.1) │ │
│ │ 接收回复数据包 │ │
│ └──────────────┬───────────────────────────────┘ │
│ ↓ │
│ ┌──────────────────────────────────────────────┐ │
│ │ Linux 网络栈(red Namespace) │ │
│ │ │ │
│ │ 1. veth-red 接收数据包 │ │
│ │ 2. IP 层:检查目标 IP(10.0.0.1) │ │
│ │ 3. ICMP 层:识别为 ICMP Echo Reply │ │
│ │ 4. 传递给 ping 进程 │ │
│ └──────────────────────────────────────────────┘ │
│ ↓ │
│ ┌──────────────────────────────────────────────┐ │
│ │ ping 进程 │ │
│ │ │ │
│ │ 收到 ICMP Echo Reply │ │
│ │ 显示:64 bytes from 10.0.0.2: ... │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ red Network Namespace │
└─────────────────────────────────────────────────────────┘
完整数据流图
bash
┌─────────────────────────────────────────────────────────┐
│ 主机 Shell │
│ $ sudo ip netns exec red ping 10.0.0.2 │
└─────────────────────────────────────────────────────────┘
│
│ 1. 切换到 red Network Namespace
↓
┌─────────────────────────────────────────────────────────┐
│ red Network Namespace │
│ ┌──────────────────────────────────────────────┐ │
│ │ ping 进程启动 │ │
│ │ - 解析目标:10.0.0.2 │ │
│ │ - 查找路由:通过 veth-red │ │
│ │ - 源 IP:10.0.0.1 │ │
│ └──────────────────────────────────────────────┘ │
│ │ │
│ │ 2. 创建 ICMP Echo Request │
│ ↓ │
│ ┌──────────────────────────────────────────────┐ │
│ │ 网络栈处理 │ │
│ │ - 封装 IP 头(10.0.0.1 -> 10.0.0.2) │ │
│ │ - 封装以太网头 │ │
│ └──────────────────────────────────────────────┘ │
│ │ │
│ │ 3. 通过 veth-red 发送 │
│ ↓ │
│ ┌──────────────────────────────────────────────┐ │
│ │ veth-red (10.0.0.1) │ │
│ │ 发送数据包 │ │
│ └──────────────┬───────────────────────────────┘ │
└─────────────────┼───────────────────────────────────────┘
│
│ 4. 通过 veth pair 传输
│ (内核直接转发)
│
┌─────────────────┼───────────────────────────────────────┐
│ ↓ │
│ ┌──────────────┴───────────────────────────────┐ │
│ │ veth-blue (10.0.0.2) │ │
│ │ 接收数据包 │ │
│ └──────────────┬───────────────────────────────┘ │
│ │ │
│ │ 5. 网络栈处理 │
│ ↓ │
│ ┌──────────────────────────────────────────────┐ │
│ │ blue Namespace 网络栈 │ │
│ │ - 检查目标 IP:10.0.0.2 ✓ │ │
│ │ - 识别 ICMP Echo Request │ │
│ │ - 内核自动生成 ICMP Echo Reply │ │
│ └──────────────────────────────────────────────┘ │
│ │ │
│ │ 6. 通过 veth-blue 发送回复 │
│ ↓ │
│ ┌──────────────────────────────────────────────┐ │
│ │ veth-blue (10.0.0.2) │ │
│ │ 发送 ICMP Echo Reply │ │
│ └──────────────┬───────────────────────────────┘ │
└─────────────────┼───────────────────────────────────────┘
│
│ 7. 通过 veth pair 返回
│
┌─────────────────┼───────────────────────────────────────┐
│ ↓ │
│ ┌──────────────┴───────────────────────────────┐ │
│ │ veth-red (10.0.0.1) │ │
│ │ 接收回复 │ │
│ └──────────────┬───────────────────────────────┘ │
│ │ │
│ │ 8. 网络栈处理 │
│ ↓ │
│ ┌──────────────────────────────────────────────┐ │
│ │ red Namespace 网络栈 │ │
│ │ - 检查目标 IP:10.0.0.1 ✓ │ │
│ │ - 识别 ICMP Echo Reply │ │
│ │ - 传递给 ping 进程 │ │
│ └──────────────────────────────────────────────┘ │
│ │ │
│ │ 9. ping 进程接收 │
│ ↓ │
│ ┌──────────────────────────────────────────────┐ │
│ │ ping 进程 │ │
│ │ 显示:64 bytes from 10.0.0.2: ... │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ red Network Namespace │
└─────────────────────────────────────────────────────────┘
完整示例:创建两个"容器"并连接
#!/bin/bash
# 创建两个 Network Namespaces 并连接它们
# 1. 创建 Namespaces
sudo ip netns add container1
sudo ip netns add container2
# 2. 创建 veth pair
sudo ip link add veth1 type veth peer name veth2
# 3. 将接口放入各自的 Namespace
sudo ip link set veth1 netns container1
sudo ip link set veth2 netns container2
# 4. 配置 IP 地址
sudo ip netns exec container1 ip addr add 10.0.0.1/24 dev veth1
sudo ip netns exec container2 ip addr add 10.0.0.2/24 dev veth2
# 5. 启动接口
sudo ip netns exec container1 ip link set veth1 up
sudo ip netns exec container2 ip link set veth2 up
# 6. 启动回环接口
sudo ip netns exec container1 ip link set lo up
sudo ip netns exec container2 ip link set lo up
# 7. 测试连通性
echo "从 container1 ping container2:"
sudo ip netns exec container1 ping -c 3 10.0.0.2
echo "从 container2 ping container1:"
sudo ip netns exec container2 ping -c 3 10.0.0.1
# 8. 查看路由表
echo "container1 的路由表:"
sudo ip netns exec container1 ip route show
echo "container2 的路由表:"
sudo ip netns exec container2 ip route show
# 9. 清理
sudo ip netns delete container1
sudo ip netns delete container2