veth 设备介绍
- veth 和其它网络设备一样,一端连接的是内核协议栈;
- veth 设备是成对存在的,另一端两个设备彼此连接;
- 一个设备收到来自协议栈的请求数据后,会将数据发送到另一台设备上去。
+----------------------------------------------------------------+
| |
| +------------------------------------------------+ |
| | Newwork Protocol Stack | |
| +------------------------------------------------+ |
| ↑ ↑ ↑ |
|..............|...............|...............|.................|
| ↓ ↓ ↓ |
| +----------+ +-----------+ +-----------+ |
| | eth0 | | veth0 | | veth1 | |
| +----------+ +-----------+ +-----------+ |
|192.168.1.11 ↑ ↑ ↑ |
| | +---------------+ |
| | 192.168.2.11 192.168.2.1 |
+--------------|-------------------------------------------------+
↓
Physical Network
物理网卡的 IP 地址为 192.168.1.11
,veth0
和 veth1
的 IP 分别为 192.168.2.11
、192.168.2.1
。
只配置一个 veth 的 IP 地址
sudo ip link add veth0 type veth peer name veth1
sudo ip addr add 192.168.2.11/24 dev veth0
sudo ip link set veth0 up
sudo ip link set veth1 up
这里给 veth0
配置 IP 地址,但是不配置 veth1
的 IP 地址,尝试 ping 一下 veth1
发现 ping 不通,通过 tcpdump
设备监听 ARP 应答包:
dev@debian:~$ sudo tcpdump -n -i veth0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on veth0, link-type EN10MB (Ethernet), capture size 262144 bytes
20:20:18.285230 ARP, Request who-has 192.168.2.1 tell 192.168.2.11, length 28
20:20:19.282018 ARP, Request who-has 192.168.2.1 tell 192.168.2.11, length 28
20:20:20.282038 ARP, Request who-has 192.168.2.1 tell 192.168.2.11, length 28
20:20:21.300320 ARP, Request who-has 192.168.2.1 tell 192.168.2.11, length 28
20:20:22.298783 ARP, Request who-has 192.168.2.1 tell 192.168.2.11, length 28
20:20:23.298923 ARP, Request who-has 192.168.2.1 tell 192.168.2.11, length 28
dev@debian:~$ sudo tcpdump -n -i veth1
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on veth1, link-type EN10MB (Ethernet), capture size 262144 bytes
20:20:48.570459 ARP, Request who-has 192.168.2.1 tell 192.168.2.11, length 28
20:20:49.570012 ARP, Request who-has 192.168.2.1 tell 192.168.2.11, length 28
20:20:50.570023 ARP, Request who-has 192.168.2.1 tell 192.168.2.11, length 28
20:20:51.570023 ARP, Request who-has 192.168.2.1 tell 192.168.2.11, length 28
20:20:52.569988 ARP, Request who-has 192.168.2.1 tell 192.168.2.11, length 28
20:20:53.570833 ARP, Request who-has 192.168.2.1 tell 192.168.2.11, length 28
可以发现 ARP 包并没有回应,ARP 协议是广播查询对应 IP 值的 MAC 地址,具体流程如下:
- ping 进程构造
ICMP echo
请求包,并通过 socket 发送给协议栈; - 协议栈根据目的 IP 地址和系统路由表查询
192.168.2.1
的数据包应该由192.168.2.11
IP 地址发送出去; - 由于是第一次访问
192.168.2.1
,且目的IP 和本地IP是在同一个网段,所以协议栈会先发送ARP
数据包出去,询问192.168.2.1
的 MAC 地址; - 协议栈将 ARP 包交给 veth0,并由它发送出去;由于 veth0 的另一端连接的是 veth1,所以
ARP
数据包转发给了 veth1; - veth1 收到 ARP 数据包后转发给另一端的协议栈;
- 协议栈的本地设备列表中由于没有
192.168.2.1
这个IP值,所以会丢弃该 ARP 数据包,这就是只能看到 ARP 请求包,但是无法查看应答包的原因。
配置两个 veth 设备的 IP 地址
给 veth1 设备配置 IP 地址:
sudo ip addr add 192.168.2.1/24 dev veth1
接着尝试 ping 192.168.2.1
这个 IP地址,输出如下:
dev@debian:~$ ping -c 4 192.168.2.1 -I veth0
PING 192.168.2.1 (192.168.2.1) from 192.168.2.11 veth0: 56(84) bytes of data.
64 bytes from 192.168.2.1: icmp_seq=1 ttl=64 time=0.032 ms
64 bytes from 192.168.2.1: icmp_seq=2 ttl=64 time=0.048 ms
64 bytes from 192.168.2.1: icmp_seq=3 ttl=64 time=0.055 ms
64 bytes from 192.168.2.1: icmp_seq=4 ttl=64 time=0.050 ms
--- 192.168.2.1 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3002ms
rtt min/avg/max/mdev = 0.032/0.046/0.055/0.009 ms
发现成功建立连接,尝试抓包结果如下:
dev@debian:~$ sudo tcpdump -n -i veth0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on veth0, link-type EN10MB (Ethernet), capture size 262144 bytes
20:23:43.113062 IP 192.168.2.11 > 192.168.2.1: ICMP echo request, id 24169, seq 1, length 64
20:23:44.112078 IP 192.168.2.11
> 192.168.2.1: ICMP echo request, id 24169, seq 2, length 64
20:23:45.111091 IP 192.168.2.11 > 192.168.2.1: ICMP echo request, id 24169, seq 3, length 64
20:23:46.110082 IP 192.168.2.11 > 192.168.2.1: ICMP echo request, id 24169, seq 4, length 64
dev@debian:~$ sudo tcpdump -n -i veth1
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on veth1, link-type EN10MB (Ethernet), capture size 262144 bytes
20:24:12.221372 IP 192.168.2.11 > 192.168.2.1: ICMP echo request, id 24174, seq 1, length 64
20:24:13.222089 IP 192.168.2.11 > 192.168.2.1: ICMP echo request, id 24174, seq 2, length 64
20:24:14.224836 IP 192.168.2.11 > 192.168.2.1: ICMP echo request, id 24174, seq 3, length 64
20:24:15.223826 IP 192.168.2.11 > 192.168.2.1: ICMP echo request, id 24174, seq 4, length 64
数据包的发送流程如下:
- ping 进程构造的
ICMP echo
请求包,并通过 socket 发送给协议栈; - 由于 ping 命令指定了数据包走
veth0
,而且本地 ARP缓存中有相关的记录,所以不再发送 ARP数据包,而是直接将数据包交给 veth0; - 由于 veth0 的一端连接着 veth1,另一端连接着网络协议栈,所以
ICMP echo
请求包转发给了veth1
; veth1
接收到请求数据包后转发给另一端的网络协议栈;- 网络协议栈查看自己的设备列表,发现有
192.168.2.1
这个IP,于是构造ICMP echo
应答包,并准备返回; - 网络协议栈查看自己的路由表,发现发往
192.168.2.1
的数据包应该走 lo口,于是将应答包发送给 lo设备; - lo设备在收到来自协议栈的应答包后,转手将数据返还给了协议栈(相当于协议栈通过发送流程把数据包发送给 lo设备,lo设备再将数据包交给协议栈);
- 协议栈接收到应答包后,发现有 socket 需要该数据包,于是交给相应的 socket;
总结
上面的介绍可以看出,从 veth0 发送出去的数据包,会转发到 veth1 上,如果目的地址是 veth1 的IP地址,就能够被网络协议栈处理,否则连 ARP数据包都无法返回。所以 veth
设备如果不借助其它虚拟设备,数据包只能在本地协议栈中循环,无法发送到外部网络。