网络命令空间简介

网络命令空间(Network Namespace)是Linux内核提供的一种隔离机制,用于创建独立的网络环境。每个命名空间拥有自己的网络接口、IP地址、路由表、防火墙规则等资源,彼此互不干扰。这类似于在单个物理主机上虚拟出多个网络栈。

其主要目的是支持容器化和虚拟化技术,例如在Docker中,每个容器运行在自己的网络命名空间内,实现资源隔离和安全性。好处包括:

  • 隔离网络配置,避免冲突(如不同容器使用相同IP)。
  • 简化测试环境搭建(如模拟多主机网络)。
  • 提升资源利用率(无需额外硬件)。

实验概述

目的:创建两个隔离的网络命名空间,并通过veth pair实现它们之间的通信


详细操作步骤说明

1. 创建网络命名空间

# 创建两个隔离的网络命名空间
sudo ip netns add ns1
sudo ip netns add ns2

# 验证创建成功
sudo ip netns list

输出ns2 ns1 - 表示两个命名空间已创建

2. 初始状态检查

# 查看主机默认命名空间的网络接口
ip addr

显示

  • lo: 回环接口
  • ens33: 物理网卡,IP为192.168.136.128/24
# 查看ns1中的初始网络接口
sudo ip netns exec ns1 ip addr

显示:只有lo接口,且状态为DOWN

3. 启用回环接口

# 启用两个命名空间的lo接口
sudo ip netns exec ns1 ip link set lo up
sudo ip netns exec ns2 ip link set lo up

# 验证lo接口状态
sudo ip netns exec ns1 ip addr show lo

显示lo状态变为UP,并自动配置了127.0.0.1/8

4. 创建并配置veth pair

# 创建一对虚拟以太网设备
sudo ip link add veth0 type veth peer name veth1

# 查看创建的veth设备
ip link show | grep veth
# 将veth设备分别移动到命名空间中
sudo ip link set veth0 netns ns1
sudo ip link set veth1 netns ns2

# 验证设备移动成功
sudo ip netns exec ns1 ip link show veth0
sudo ip netns exec ns2 ip link show veth1

5. 配置IP地址并启用接口

# 为ns1的veth0配置IP并启用
sudo ip netns exec ns1 ip addr add 10.0.0.1/24 dev veth0
sudo ip netns exec ns1 ip link set veth0 up

# 为ns2的veth1配置IP并启用
sudo ip netns exec ns2 ip addr add 10.0.0.2/24 dev veth1
sudo ip netns exec ns2 ip link set veth1 up

6. 测试连通性

# 从ns1 ping ns2
sudo ip netns exec ns1 ping -c 3 10.0.0.2

# 从ns2 ping ns1  
sudo ip netns exec ns2 ping -c 3 10.0.0.1

结果:双向ping通,延迟约0.03ms,证明两个命名空间可以通信

7. 验证路由配置

# 查看ns1的路由表
sudo ip netns exec ns1 ip route
# 输出:10.0.0.0/24 dev veth0 proto kernel scope link src 10.0.0.1

# 查看ns2的路由表
sudo ip netns exec ns2 ip route
# 输出:10.0.0.0/24 dev veth1 proto kernel scope link src 10.0.0.2

# 查看主机路由表
ip route
# 输出:默认路由指向192.168.136.2 via ens33

技术要点总结

核心概念

  1. 网络命名空间:隔离的网络栈实例,拥有独立的接口、路由表、iptables规则等
  2. veth pair:成对出现的虚拟以太网设备,像一根虚拟网线连接两个命名空间
  3. 网络隔离:ns1和ns2与主机默认命名空间完全隔离

网络拓扑

ns1 (10.0.0.1) <--veth pair--> ns2 (10.0.0.2)
    veth0                          veth1

关键命令说明

  • ip netns add <name>:创建命名空间
  • ip netns exec <name> <command>:在指定命名空间执行命令
  • ip link add type veth peer name:创建veth设备对
  • ip link set <dev> netns <name>:将设备移动到命名空间

这个实验成功演示了Linux网络虚拟化的基础,常用于容器网络、网络测试等场景。




三节点网络拓扑实验

通过 Linux ip netns 命名空间机制,构建一个虚拟的三节点网络拓扑,包括两个终端主机(ns1、ns2)和一个路由器(router)。
目标是验证 Linux 网络命名空间之间的隔离与连通性原理,掌握虚拟以太网接口(veth pair)与 IP 转发机制的配置。


二、实验原理

  1. 网络命名空间(Network Namespace)
    每个 namespace 拥有独立的网络栈(接口、路由表、ARP 缓存等)。
    命名空间之间默认隔离,但可以通过 veth pair 连接形成虚拟网络。

  2. veth pair(虚拟网线)
    veth 设备成对出现,一端发出的数据包会从另一端接收。
    它常用于跨 namespace 通信,相当于一根虚拟网线。

  3. 路由器转发机制(IP Forwarding)
    当开启 net.ipv4.ip_forward=1 时,Linux 内核可以像真实路由器一样转发来自不同子网的包。


三、实验拓扑(Mermaid 拓扑图)

命名空间 ns2
命名空间 router
命名空间 ns1
veth2-ns2
192.168.2.10/24
veth1-router
192.168.1.1/24
veth2-router
192.168.2.1/24
veth1-ns1
192.168.1.10/24

🔹 说明

  • ns1ns2 分别代表两个不同子网:192.168.1.0/24 与 192.168.2.0/24。
  • router 担任三层转发角色,实现两个子网间的通信。
  • veth1-*veth2-* 是虚拟网卡对,连接不同命名空间。

四、实验过程详细解析

Step 1. 创建命名空间

sudo ip netns add ns1
sudo ip netns add ns2
sudo ip netns add router

✅ 成功创建 3 个命名空间。


Step 2. 创建并分配 veth pair

sudo ip link add veth1-ns1 type veth peer name veth1-router
sudo ip link add veth2-ns2 type veth peer name veth2-router

这创建了两对虚拟网卡(veth 对),相当于两根“虚拟网线”。


Step 3. 将 veth 接口移动到命名空间

sudo ip link set veth1-ns1 netns ns1
sudo ip link set veth1-router netns router
sudo ip link set veth2-ns2 netns ns2
sudo ip link set veth2-router netns router

✅ 每个命名空间现在有自己的接口,彼此独立。


Step 4. 为各接口配置 IP 地址

sudo ip netns exec ns1 ip addr add 192.168.1.10/24 dev veth1-ns1
sudo ip netns exec ns2 ip addr add 192.168.2.10/24 dev veth2-ns2
sudo ip netns exec router ip addr add 192.168.1.1/24 dev veth1-router
sudo ip netns exec router ip addr add 192.168.2.1/24 dev veth2-router

Step 5. 启动接口

sudo ip netns exec ns1 ip link set lo up
sudo ip netns exec ns1 ip link set veth1-ns1 up
sudo ip netns exec ns2 ip link set lo up
sudo ip netns exec ns2 ip link set veth2-ns2 up
sudo ip netns exec router ip link set lo up
sudo ip netns exec router ip link set veth1-router up
sudo ip netns exec router ip link set veth2-router up

Step 6. 开启路由器的 IP 转发功能

sudo ip netns exec router sysctl -w net.ipv4.ip_forward=1

✅ 输出显示:

net.ipv4.ip_forward = 1

说明路由器现在具备跨子网转发能力。


Step 7. 设置默认路由

sudo ip netns exec ns1 ip route add default via 192.168.1.1
sudo ip netns exec ns2 ip route add default via 192.168.2.1

✅ 这一步确保 ns1ns2 的数据包能够通过 router 进行转发。


五、实验结果验证

✅ 连通性测试

1. ns1 → ns2 跨网段通信
sudo ip netns exec ns1 ping -c 3 192.168.2.10

输出:

3 packets transmitted, 3 received, 0% packet loss

说明数据包成功经 router 转发到达 ns2。

2. ns2 → ns1 反向通信
sudo ip netns exec ns2 ping -c 3 192.168.1.10

同样 0% 丢包,说明双向通信正常。

3. 各自 ping 默认网关(路由器)
sudo ip netns exec ns1 ping -c 3 192.168.1.1
sudo ip netns exec ns2 ping -c 3 192.168.2.1

返回 TTL=64,说明路由器接口工作正常。


六、实验结果分析

测试项目 预期结果 实际结果 结论
命名空间创建 成功 成功 OK
veth 配置 成功 成功 OK
IP 地址与路由配置 正确 正确 OK
路由器转发 正常 正常 OK
ns1 ↔ ns2 连通性 能通信 能通信 ✅ 成功

实验验证了:

  • 网络命名空间可以实现隔离与虚拟网络构建;
  • veth pair 可以在命名空间间建立“虚拟链路”;
  • 开启 ip_forward 后,Linux 完全可以充当三层路由器角色。

七、结论与拓展

  1. 本实验成功构建了一个纯软件虚拟网络,结构清晰、逻辑正确。

  2. 通过 ip netns 工具可轻松模拟多主机网络环境,无需真实物理设备。

  3. 若进一步拓展:

    • 可添加 NAT 转换(用 iptables -t nat 模拟访问外网);
    • 可引入 bridge 模拟交换机;
    • 可测试 tc 延迟、丢包模拟网络性能。

好的。下面把你在每一步验证时看到的返回值/输出逐行“读懂”,说明它们各自代表什么、是否符合预期、若异常应如何判断与处理。为便于查找,我按你执行的实际顺序分组解析。


1)命名空间相关

ip netns list

返回(最初为空):

root@ubuntu24:/home/keson# sudo ip netns list
(空)
  • 含义:当前系统中还没有持久化的 network namespace(文件位于 /run/netns)。
  • 结论:正常;尚未创建。

ip link show(宿主机)

3: veth1-router@veth1-ns1: <BROADCAST,MULTICAST,M-DOWN> ... state DOWN ...
4: veth1-ns1@veth1-router: <BROADCAST,MULTICAST,M-DOWN> ... state DOWN ...
5: veth2-router@veth2-ns2: <BROADCAST,MULTICAST,M-DOWN> ... state DOWN ...
6: veth2-ns2@veth2-router: <BROADCAST,MULTICAST,M-DOWN> ... state DOWN ...
  • @ 含义:显示对端接口名(veth 成对出现,这里彼此指向对方)。
  • M-DOWNcarrier(物理层)未 up。对 veth 来说,只有两端都处于 up,链路层才会 LOWER_UP
  • state DOWN:接口未 ip link set ... up
  • 结论:符合刚创建后的默认状态。

3)将 veth 移入各命名空间

ip link set <ifname> netns <ns>

无显式输出(返回 0)

  • 含义:接口成功移动到对应 ns。

宿主机再次查找:

ip link show | grep -E "veth1-ns1|veth1-router|veth2-ns2|veth2-router"
(无输出)
  • 含义:这些接口已不在宿主机网络栈,而是在各自的 namespace 中。
  • 结论:符合预期。

进入各 ns 查看接口

ns1: 4: veth1-ns1@if3: <BROADCAST,MULTICAST> ... state DOWN ...
router: 3: veth1-router@if4: ...
        5: veth2-router@if6: ...
ns2: 6: veth2-ns2@if5: ...
  • @if3/@if4:显示对端接口的 ifindex(内核索引),可忽略。
  • state DOWN:仍未 up
  • 结论:移动成功,状态待配置。

4)配置 IP 地址

ip addr add ... dev <if>

无显式输出(返回 0)

  • 含义:为接口分配 IPv4 地址成功。

查看地址(仍未 up)

inet 192.168.1.10/24 scope global veth1-ns1
link-netns router
  • inet .../24:IPv4 地址与掩码设置正确。
  • link-netns router:对端接口位于 router 命名空间(有助于排错)。
  • 结论:IP 配置正确。

5)接口 up 与 loopback 启动

ip link set lo up + ip link set veth* up

无显式输出(返回 0)

再次查看(后续汇总)

你在后面一次性展示了完整地址、路由和链路层状态,重点解读:

  • <...UP,LOWER_UP>

    • UP:接口被管理地置为 up;
    • LOWER_UP:链路层“载波”已 up(对 veth 而言需两端都 up)。
  • qdisc noqueue:此类虚拟接口没有复杂队列规则,是常见默认值。

  • state UP:接口运行中。

结论:接口均已正确拉起。


6)开启路由转发

sysctl -w net.ipv4.ip_forward=1

net.ipv4.ip_forward = 1
  • 含义:在 router 命名空间内,内核三层转发开启。
  • 二次确认 sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1
  • 结论:路由器具备跨子网转发能力。

7)配置默认路由

ip route add default via ...(在 ns1/ns2)

无显式输出(返回 0)

ip route(在 ns1)

default via 192.168.1.1 dev veth1-ns1
192.168.1.0/24 dev veth1-ns1 proto kernel scope link src 192.168.1.10
  • default via ...:默认网关指向 router 对应接口。
  • proto kernel scope link src ...:本子网直连路由,由内核自动生成。
  • 结论:路由表正确;ns2 的输出与之对应(换成 192.168.2.0/24 与 192.168.2.1)。

ip addr show(在 router)

192.168.1.0/24 dev veth1-router ... src 192.168.1.1
192.168.2.0/24 dev veth2-router ... src 192.168.2.1
  • 含义:router 对两个子网均为直连网络,无需额外静态路由。
  • 结论:符合三层路由器角色。

8)连通性验证(ping)

A)跨网段:ns1 → ns2

64 bytes from 192.168.2.10: icmp_seq=1 ttl=63 time=0.051 ms
...
--- 192.168.2.10 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss
rtt min/avg/max/mdev = 0.036/0.049/0.061/0.010 ms
  • 0% packet loss:三次 ICMP 往返均成功。

  • time=...ms:往返时延(RTT),veth 内核路径极短,微秒~低毫秒级正常。

  • ttl=63(重点)

    • Linux 发包默认 TTL=64;
    • 经过 router 转发时,TTL 在转发处会 减 1
    • 收到回显应答时显示的 TTL=63 → 说明确实经过了一跳(router)
  • 结论跨子网转发有效,路径正确(经 router)。

B)反向:ns2 → ns1

ttl=63
0% packet loss
  • 含义:同理,双向通信路径经 router,TTL=63 符合“过一跳”的规律。
  • 结论双向跨网段连通

C)同网段:各自 ping 默认网关(ns1 → 192.168.1.1、ns2 → 192.168.2.1)

ttl=64
  • 原因:与自己在同一命名空间、同一子网里的接口通信,不经过三层转发(或认为不跨“下一跳”),TTL 不会被减 1
  • 结论ttl=64同子网直连的“金标准”现象;与上面 ttl=63 形成对比,充分证明路由转发只发生在跨子网时。

小结:

  • ttl=64:本 ns 内直连;
  • ttl=63:跨 router 转发 1 跳;
  • 若出现 ttl=62,意味着还多过了一跳(例如再串一个路由节点)。


10)若验证出现异常,如何用返回值快速定位

  • ping 100% 丢包
    1)看 routersysctl net.ipv4.ip_forward 是否为 1
    2)看 ip link show 是否 UP,LOWER_UP
    3)看 ns1/ns2ip route 是否存在正确的 default via
    4)ip addr show 是否 IP/掩码配置错误或落在同网段冲突。

  • ttl 异常

    • 应为 64(直连)或 63(跨一跳);若仍是 64 且你预期跨网段,说明实际未过路由器(比如路由/掩码错误导致被认为直连)。
    • 若是 62 或更低,说明多了一跳,可能又插入了额外节点或宿主机 netfilter 做了转发。
  • 接口 state DOWN / 无 LOWER_UP

    • ip link set <if> up
    • veth 需要两端都 up 才会 LOWER_UP
    • 若移入错误 ns,会在该 ns 里找不到,宿主机也查不到(需在目标 ns 查询)。
  • Cannot create namespace file ... File exists

    • 表示命名空间已存在;用 ip netns list 确认即可。并不影响后续。

11)对你的验证结果的“对照判定”(一眼看懂)

验证点 你看到的关键返回值 解释 是否达标
命名空间存在 router / ns1 / ns2 三个 ns 就绪
veth 初始状态 <...,M-DOWN> state DOWN 刚创建,未 up,未连通 ✅(随后会 up)
移入 ns 宿主机查不到,ns 内可见 已成功移入目标 ns
配置 IP inet x.x.x.x/24 地址/掩码正确
接口 up <...,UP,LOWER_UP> 两端均 up,链路就绪
路由转发 net.ipv4.ip_forward = 1 路由器具备转发功能
路由表 default via ... + 直连路由 默认网关与直连均正确
跨网段 ping ttl=63、0% 丢包 经过 1 跳 router 转发
同网段 ping 网关 ttl=64 直连,无减 TTL

结论

  • 你每一步验证返回值都符合预期:接口状态从 DOWN/M-DOWNUP/LOWER_UP,路由器转发开启为 1,路由表正确,跨网段 TTL=63同网段 TTL=64 的对照强力佐证了三层转发路径与直连路径的差别。

八、结果和验证

root@ubuntu24:/home/keson# sudo ip netns exec ns1 ping -c 3 192.168.1.1
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=0.027 ms
64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=0.039 ms
64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=0.038 ms

--- 192.168.1.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2036ms
rtt min/avg/max/mdev = 0.027/0.034/0.039/0.005 ms
root@ubuntu24:/home/keson# sudo ip netns exec ns2 ping -c 3 192.168.2.1
PING 192.168.2.1 (192.168.2.1) 56(84) bytes of data.
64 bytes from 192.168.2.1: icmp_seq=1 ttl=64 time=0.028 ms
64 bytes from 192.168.2.1: icmp_seq=2 ttl=64 time=0.036 ms
64 bytes from 192.168.2.1: icmp_seq=3 ttl=64 time=0.040 ms

--- 192.168.2.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2048ms
rtt min/avg/max/mdev = 0.028/0.034/0.040/0.005 ms
root@ubuntu24:/home/keson# sudo ip netns exec ns1 ping -c 3 192.168.2.10
PING 192.168.2.10 (192.168.2.10) 56(84) bytes of data.
64 bytes from 192.168.2.10: icmp_seq=1 ttl=63 time=0.031 ms
64 bytes from 192.168.2.10: icmp_seq=2 ttl=63 time=0.050 ms
64 bytes from 192.168.2.10: icmp_seq=3 ttl=63 time=0.049 ms

--- 192.168.2.10 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2065ms
rtt min/avg/max/mdev = 0.031/0.043/0.050/0.008 ms
root@ubuntu24:/home/keson# sudo ip netns exec ns2 ping -c 3 192.168.1.10
PING 192.168.1.10 (192.168.1.10) 56(84) bytes of data.
64 bytes from 192.168.1.10: icmp_seq=1 ttl=63 time=0.044 ms
64 bytes from 192.168.1.10: icmp_seq=2 ttl=63 time=0.049 ms
64 bytes from 192.168.1.10: icmp_seq=3 ttl=63 time=0.049 ms

--- 192.168.1.10 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2033ms
rtt min/avg/max/mdev = 0.044/0.047/0.049/0.002 ms


keson@ubuntu24:~$ sudo ip netns exec ns1 tcpdump -i veth1-ns1 -nn -l -v icmp
tcpdump: listening on veth1-ns1, link-type EN10MB (Ethernet), snapshot length 262144 bytes
00:59:28.076528 IP (tos 0x0, ttl 64, id 59581, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.1.1: ICMP echo request, id 5672, seq 1, length 64
00:59:28.076545 IP (tos 0x0, ttl 64, id 40486, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.1.1 > 192.168.1.10: ICMP echo reply, id 5672, seq 1, length 64
00:59:29.090051 IP (tos 0x0, ttl 64, id 60281, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.1.1: ICMP echo request, id 5672, seq 2, length 64
00:59:29.090072 IP (tos 0x0, ttl 64, id 40814, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.1.1 > 192.168.1.10: ICMP echo reply, id 5672, seq 2, length 64
00:59:30.114207 IP (tos 0x0, ttl 64, id 61026, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.1.1: ICMP echo request, id 5672, seq 3, length 64
00:59:30.114227 IP (tos 0x0, ttl 64, id 40839, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.1.1 > 192.168.1.10: ICMP echo reply, id 5672, seq 3, length 64
01:00:15.344266 IP (tos 0x0, ttl 64, id 30699, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.2.10: ICMP echo request, id 5963, seq 1, length 64
01:00:15.344289 IP (tos 0x0, ttl 63, id 22249, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.1.10: ICMP echo reply, id 5963, seq 1, length 64
01:00:16.386388 IP (tos 0x0, ttl 64, id 31026, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.2.10: ICMP echo request, id 5963, seq 2, length 64
01:00:16.386417 IP (tos 0x0, ttl 63, id 22952, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.1.10: ICMP echo reply, id 5963, seq 2, length 64
01:00:17.409830 IP (tos 0x0, ttl 64, id 32004, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.2.10: ICMP echo request, id 5963, seq 3, length 64
01:00:17.409860 IP (tos 0x0, ttl 63, id 23748, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.1.10: ICMP echo reply, id 5963, seq 3, length 64
01:00:20.176476 IP (tos 0x0, ttl 63, id 24968, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.1.10: ICMP echo request, id 5997, seq 1, length 64
01:00:20.176484 IP (tos 0x0, ttl 64, id 32091, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.2.10: ICMP echo reply, id 5997, seq 1, length 64
01:00:21.185957 IP (tos 0x0, ttl 63, id 25487, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.1.10: ICMP echo request, id 5997, seq 2, length 64
01:00:21.185968 IP (tos 0x0, ttl 64, id 32639, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.2.10: ICMP echo reply, id 5997, seq 2, length 64
01:00:22.210169 IP (tos 0x0, ttl 63, id 25550, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.1.10: ICMP echo request, id 5997, seq 3, length 64
01:00:22.210179 IP (tos 0x0, ttl 64, id 32920, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.2.10: ICMP echo reply, id 5997, seq 3, length 64


root@ubuntu24:/home/keson# sudo ip netns exec router tcpdump -i any -nn -l -v icmp
tcpdump: data link type LINUX_SLL2
tcpdump: listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
00:59:28.076532 veth1-router In  IP (tos 0x0, ttl 64, id 59581, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.1.1: ICMP echo request, id 5672, seq 1, length 64
00:59:28.076544 veth1-router Out IP (tos 0x0, ttl 64, id 40486, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.1.1 > 192.168.1.10: ICMP echo reply, id 5672, seq 1, length 64
00:59:29.090056 veth1-router In  IP (tos 0x0, ttl 64, id 60281, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.1.1: ICMP echo request, id 5672, seq 2, length 64
00:59:29.090071 veth1-router Out IP (tos 0x0, ttl 64, id 40814, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.1.1 > 192.168.1.10: ICMP echo reply, id 5672, seq 2, length 64
00:59:30.114212 veth1-router In  IP (tos 0x0, ttl 64, id 61026, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.1.1: ICMP echo request, id 5672, seq 3, length 64
00:59:30.114226 veth1-router Out IP (tos 0x0, ttl 64, id 40839, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.1.1 > 192.168.1.10: ICMP echo reply, id 5672, seq 3, length 64
01:00:07.937478 veth2-router In  IP (tos 0x0, ttl 64, id 36745, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.2.1: ICMP echo request, id 5916, seq 1, length 64
01:00:07.937486 veth2-router Out IP (tos 0x0, ttl 64, id 56364, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.2.1 > 192.168.2.10: ICMP echo reply, id 5916, seq 1, length 64
01:00:08.962506 veth2-router In  IP (tos 0x0, ttl 64, id 36904, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.2.1: ICMP echo request, id 5916, seq 2, length 64
01:00:08.962519 veth2-router Out IP (tos 0x0, ttl 64, id 56722, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.2.1 > 192.168.2.10: ICMP echo reply, id 5916, seq 2, length 64
01:00:09.985933 veth2-router In  IP (tos 0x0, ttl 64, id 37627, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.2.1: ICMP echo request, id 5916, seq 3, length 64
01:00:09.985947 veth2-router Out IP (tos 0x0, ttl 64, id 57314, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.2.1 > 192.168.2.10: ICMP echo reply, id 5916, seq 3, length 64
01:00:15.344269 veth1-router In  IP (tos 0x0, ttl 64, id 30699, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.2.10: ICMP echo request, id 5963, seq 1, length 64
01:00:15.344275 veth2-router Out IP (tos 0x0, ttl 63, id 30699, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.2.10: ICMP echo request, id 5963, seq 1, length 64
01:00:15.344285 veth2-router In  IP (tos 0x0, ttl 64, id 22249, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.1.10: ICMP echo reply, id 5963, seq 1, length 64
01:00:15.344288 veth1-router Out IP (tos 0x0, ttl 63, id 22249, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.1.10: ICMP echo reply, id 5963, seq 1, length 64
01:00:16.386393 veth1-router In  IP (tos 0x0, ttl 64, id 31026, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.2.10: ICMP echo request, id 5963, seq 2, length 64
01:00:16.386401 veth2-router Out IP (tos 0x0, ttl 63, id 31026, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.2.10: ICMP echo request, id 5963, seq 2, length 64
01:00:16.386413 veth2-router In  IP (tos 0x0, ttl 64, id 22952, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.1.10: ICMP echo reply, id 5963, seq 2, length 64
01:00:16.386416 veth1-router Out IP (tos 0x0, ttl 63, id 22952, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.1.10: ICMP echo reply, id 5963, seq 2, length 64
01:00:17.409835 veth1-router In  IP (tos 0x0, ttl 64, id 32004, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.2.10: ICMP echo request, id 5963, seq 3, length 64
01:00:17.409843 veth2-router Out IP (tos 0x0, ttl 63, id 32004, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.2.10: ICMP echo request, id 5963, seq 3, length 64
01:00:17.409856 veth2-router In  IP (tos 0x0, ttl 64, id 23748, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.1.10: ICMP echo reply, id 5963, seq 3, length 64
01:00:17.409859 veth1-router Out IP (tos 0x0, ttl 63, id 23748, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.1.10: ICMP echo reply, id 5963, seq 3, length 64
01:00:20.176467 veth2-router In  IP (tos 0x0, ttl 64, id 24968, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.1.10: ICMP echo request, id 5997, seq 1, length 64
01:00:20.176473 veth1-router Out IP (tos 0x0, ttl 63, id 24968, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.1.10: ICMP echo request, id 5997, seq 1, length 64
01:00:20.176486 veth1-router In  IP (tos 0x0, ttl 64, id 32091, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.2.10: ICMP echo reply, id 5997, seq 1, length 64
01:00:20.176488 veth2-router Out IP (tos 0x0, ttl 63, id 32091, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.2.10: ICMP echo reply, id 5997, seq 1, length 64
01:00:21.185947 veth2-router In  IP (tos 0x0, ttl 64, id 25487, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.1.10: ICMP echo request, id 5997, seq 2, length 64
01:00:21.185956 veth1-router Out IP (tos 0x0, ttl 63, id 25487, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.1.10: ICMP echo request, id 5997, seq 2, length 64
01:00:21.185969 veth1-router In  IP (tos 0x0, ttl 64, id 32639, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.2.10: ICMP echo reply, id 5997, seq 2, length 64
01:00:21.185972 veth2-router Out IP (tos 0x0, ttl 63, id 32639, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.2.10: ICMP echo reply, id 5997, seq 2, length 64
01:00:22.210159 veth2-router In  IP (tos 0x0, ttl 64, id 25550, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.1.10: ICMP echo request, id 5997, seq 3, length 64
01:00:22.210168 veth1-router Out IP (tos 0x0, ttl 63, id 25550, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.1.10: ICMP echo request, id 5997, seq 3, length 64
01:00:22.210180 veth1-router In  IP (tos 0x0, ttl 64, id 32920, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.2.10: ICMP echo reply, id 5997, seq 3, length 64
01:00:22.210183 veth2-router Out IP (tos 0x0, ttl 63, id 32920, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.2.10: ICMP echo reply, id 5997, seq 3, length 64




root@ubuntu24:/home/keson# sudo ip netns exec ns2 tcpdump -i veth2-ns2 -nn -l -v icmp
tcpdump: listening on veth2-ns2, link-type EN10MB (Ethernet), snapshot length 262144 bytes
01:00:07.937474 IP (tos 0x0, ttl 64, id 36745, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.2.1: ICMP echo request, id 5916, seq 1, length 64
01:00:07.937487 IP (tos 0x0, ttl 64, id 56364, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.2.1 > 192.168.2.10: ICMP echo reply, id 5916, seq 1, length 64
01:00:08.962501 IP (tos 0x0, ttl 64, id 36904, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.2.1: ICMP echo request, id 5916, seq 2, length 64
01:00:08.962520 IP (tos 0x0, ttl 64, id 56722, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.2.1 > 192.168.2.10: ICMP echo reply, id 5916, seq 2, length 64
01:00:09.985927 IP (tos 0x0, ttl 64, id 37627, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.2.1: ICMP echo request, id 5916, seq 3, length 64
01:00:09.985948 IP (tos 0x0, ttl 64, id 57314, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.2.1 > 192.168.2.10: ICMP echo reply, id 5916, seq 3, length 64
01:00:15.344276 IP (tos 0x0, ttl 63, id 30699, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.2.10: ICMP echo request, id 5963, seq 1, length 64
01:00:15.344285 IP (tos 0x0, ttl 64, id 22249, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.1.10: ICMP echo reply, id 5963, seq 1, length 64
01:00:16.386402 IP (tos 0x0, ttl 63, id 31026, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.2.10: ICMP echo request, id 5963, seq 2, length 64
01:00:16.386412 IP (tos 0x0, ttl 64, id 22952, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.1.10: ICMP echo reply, id 5963, seq 2, length 64
01:00:17.409844 IP (tos 0x0, ttl 63, id 32004, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.2.10: ICMP echo request, id 5963, seq 3, length 64
01:00:17.409855 IP (tos 0x0, ttl 64, id 23748, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.1.10: ICMP echo reply, id 5963, seq 3, length 64
01:00:20.176463 IP (tos 0x0, ttl 64, id 24968, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.1.10: ICMP echo request, id 5997, seq 1, length 64
01:00:20.176489 IP (tos 0x0, ttl 63, id 32091, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.2.10: ICMP echo reply, id 5997, seq 1, length 64
01:00:21.185942 IP (tos 0x0, ttl 64, id 25487, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.1.10: ICMP echo request, id 5997, seq 2, length 64
01:00:21.185973 IP (tos 0x0, ttl 63, id 32639, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.2.10: ICMP echo reply, id 5997, seq 2, length 64
01:00:22.210153 IP (tos 0x0, ttl 64, id 25550, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.2.10 > 192.168.1.10: ICMP echo request, id 5997, seq 3, length 64
01:00:22.210184 IP (tos 0x0, ttl 63, id 32920, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.1.10 > 192.168.2.10: ICMP echo reply, id 5997, seq 3, length 64



一、Ping 输出解读

1)同网段:ns1 → 192.168.1.1ns2 → 192.168.2.1

64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=0.027 ms
...
rtt min/avg/max/mdev = 0.027/0.034/0.039/0.005 ms
  • 目标:各自命名空间内的“网关口”(router 的直连接口)。
  • ttl=64:回包由 router 自身产生(本机回应),未经过转发,因此 TTL 是默认初始值 64。
  • 时延 ~0.03 ms:命名空间 + veth 内核路径,极短延迟,符合预期。
  • 0% packet loss:无丢包,链路与 IP 配置正确。

结论:本地子网连通,router 两侧接口工作正常;此类 ping 不涉及三层转发,TTL 不会被减 1。

2)跨网段:ns1 ↔ ns2

ns1 → 192.168.2.10:  ttl=63
ns2 → 192.168.1.10:  ttl=63
  • ttl=63:Linux 发包默认 TTL=64,跨一跳路由器后 TTL 减 1 → 63。
  • 对称性:两个方向相同,说明双向经 router 转发各 1 跳
  • 时延 ~0.03–0.05 ms:同样是内核级虚拟路径,符合预期。

结论:跨子网三层转发成功,且路径只有 1 跳(router)。


二、ns1 上的 tcpdump(veth1-ns1)逐行要点

示例片段:

IP (tos 0x0, ttl 64, id 59581, flags [DF], length 84) 192.168.1.10 > 192.168.1.1: ICMP echo request id 5672 seq 1
IP (tos 0x0, ttl 64, id 40486, flags [none], length 84) 192.168.1.1 > 192.168.1.10: ICMP echo reply   id 5672 seq 1
...
IP (tos 0x0, ttl 64, id 30699, flags [DF], length 84) 192.168.1.10 > 192.168.2.10: ICMP echo request id 5963 seq 1
IP (tos 0x0, ttl 63, id 22249, flags [none], length 84) 192.168.2.10 > 192.168.1.10: ICMP echo reply   id 5963 seq 1
  • ttl 64(本机发出):ns1 发出的请求默认 TTL=64。
  • ttl 63(跨网段收到的回复):从 ns2 返回的应答在 router 处 TTL 减 1,因此 ns1 看到 63。
  • flags [DF]:IP 头 Don’t Fragment 置位;Linux 进行 PMTU 发现的默认行为。用 84 字节不会触发分片,这里仅表明 DF 位为 1。
  • length 84:IP 总长度 = 20(IP头) + 8(ICMP头) + 56(默认 ping 负载)= 84。
  • id 59581/40486/...(IP Identification):这是 IP 层的 ID,由发送主机的 IP 栈生成;请求与应答来自不同主机,因此 ID 序列各自独立。
  • ICMP id 5963, seq N:这是 ICMP 层的标识与序号,用于把请求和回应配对(同一对话中 id 不变,seq 递增)。

关键信号:**同网段的回包 TTL=64;跨网段的回包 TTL=63。**这正是“是否经过路由器”的直接证据。


三、router 上的 tcpdump(-i any)逐行要点

示例片段(已标出接口与方向):

veth1-router In  IP ... ttl 64 ... 192.168.1.10 > 192.168.2.10: ICMP echo request id 5963 seq 1
veth2-router Out IP ... ttl 63 ... 192.168.1.10 > 192.168.2.10: ICMP echo request id 5963 seq 1

veth2-router In  IP ... ttl 64 ... 192.168.2.10 > 192.168.1.10: ICMP echo reply   id 5963 seq 1
veth1-router Out IP ... ttl 63 ... 192.168.2.10 > 192.168.1.10: ICMP echo reply   id 5963 seq 1
  • vethX-router In/Out:Linux cooked capture(SLL2)会标注**“相对该接口的入/出方向”**。

    • In 表示这个包是从该接口收到的(进入 router);
    • Out 表示这个包是从该接口发出的(离开 router)。
  • TTL 的变化

    • 入 veth1 时 ttl 64 → 出 veth2 时 ttl 63
    • 入 veth2 时 ttl 64 → 出 veth1 时 ttl 63
      清晰地看到路由器在转发时把 TTL 减 1
  • IP 头 id 的保留:注意这两行(同一个请求包)——

    In  ... id 30699 ...
    Out ... id 30699 ...
    

    转发不会改变 IP Identification(除非发生分片),因此 In/Out 的 IP ID 相同,证明这是同一数据包被转发。

  • 同网段 ping 网关(例如 ns1→192.168.1.1)时,你看到:

    • veth1-router In 的 echo request(目标就是 router 自己);
    • 随后 veth1-router Out 的 echo reply(由 router 产生的新包,默认 TTL=64)。
      → 这不涉及跨接口转发,只是本机应答

关键信号:In→Out 成对出现 + TTL 从 64 变 63 + IP ID 不变 = “这是同一个 IP 包被路由器三层转发”的铁证。


四、ns2 上的 tcpdump(veth2-ns2)逐行要点

示例片段:

IP ... ttl 63 ... 192.168.1.10 > 192.168.2.10: ICMP echo request id 5963 seq 1
IP ... ttl 64 ... 192.168.2.10 > 192.168.1.10: ICMP echo reply   id 5963 seq 1
  • 请求到达 ns2 时 ttl=63:表明此请求从 ns1 来,经 router 一跳;
  • ns2 发出的回包 ttl=64:回包的初始 TTL;随后在 router 转发回 ns1 时会变为 63(你在 router 与 ns1 的抓包中已经看到了)。

关键信号:到达端看到的跨网段请求 TTL=63,与 ns1/route 抓包共同构成完整的路径链条。


五、字段速查表

字段 出现位置 含义 与本实验的关系
ttl IP 头 生存时间(每经一跳减 1) 同网段回包=64;跨网段=63(经 1 跳 router)
flags [DF] IP 头 不分片标志 Linux PMTU 默认置位;本实验报文很小,不会分片
length 84 IP 头 IP 总长 20(IP) + 8(ICMP) + 56(负载)
id <number> IP 头 IP Identification 转发过程中 保持不变;不同主机各自递增
ICMP id/seq ICMP 头 会话标识与序号 匹配 request/reply 对
In/Out(SLL2) router 抓包 相对接口方向 证明入/出路由器的每一步
接口名 vethX-router router 抓包 入/出具体哪条链路 证明“从 ns1 侧进、从 ns2 侧出”(及反向)

六、结论

  • 同网段连通ns1→192.168.1.1ns2→192.168.2.1 的回包 TTL=64,表明报文在路由器本机终止与产生,无路由跳转。
  • 跨网段转发ns1↔ns2 的请求/应答在路由器处出现 成对的 In/Out 记录TTL 从 64 变 63,且 IP Identification 在转发前后保持一致,证实同一 IP 包完成了一跳三层转发。

七、TTL 变化:

TTL 变化:

ns1 (192.168.1.10) router veth1 (192.168.1.1) router veth2 (192.168.2.1) ns2 (192.168.2.10) ICMP Echo (ttl=64, IPID=X) 转发 Echo (ttl=63, IPID=X) 交付 Echo (ttl=63, IPID=X) Echo Reply (ttl=64, IPID=Y) 转发 Reply (ttl=63, IPID=Y) 交付 Reply (ttl=63, IPID=Y) ns1 (192.168.1.10) router veth1 (192.168.1.1) router veth2 (192.168.2.1) ns2 (192.168.2.10)

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐