Linux网络设备veth pair和netns
虚拟网络拓扑的实现当然离不开虚拟网络设备的参与,今天我们就来介绍一下Linux上的网络设备veth pair和netns。
Veth Pair 虚拟网络接口
veth pari是成对出现的一种虚拟网络设备接口,一端连着网络协议栈,一端彼此相连。如下图所示:
由于它的这个特性,常常被用于构建虚拟网络拓扑。例如连接两个不同的网络命名空间(Network Namespace),连接docker容器等,其中一个很常见的案例就是OpenStack Neutron底层用它来构建非常复杂的网络拓扑。
配置veth pair
创建一对veth pair
ip link add veth0 type veth peer name veth1
分别给这两个虚拟网卡启动并设置IP
ip link set veth0 up
ip addr add 10.0.0.1/24 dev veth0
ip link set veth1 up
ip addr add 10.0.0.2/24 dev veth1
此时的网络配置情况如下图
验证网络
确认网卡是否正确启动
# 查看网卡
ifconfig
# 输出
veth0: flags=4163 mtu 1500
inet 10.0.0.1 netmask 255.255.255.0 broadcast 0.0.0.0
inet6 fe80::4880:cff:fe37:b9de prefixlen 64 scopeid 0x20
ether 4a:80:0c:37:b9:de txqueuelen 1000 (Ethernet)
RX packets 7 bytes 578 (578.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 7 bytes 578 (578.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
veth1: flags=4163 mtu 1500
inet 10.0.0.2 netmask 255.255.255.0 broadcast 0.0.0.0
inet6 fe80::c094:68ff:feed:451d prefixlen 64 scopeid 0x20
ether c2:94:68:ed:45:1d txqueuelen 1000 (Ethernet)
RX packets 7 bytes 578 (578.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 7 bytes 578 (578.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
测试Veth Pair 的连通性
# 在宿主机器上ping veth0
ping 10.0.0.1
# 输出
PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data.
64 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=0.051 ms
64 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=0.039 ms
64 bytes from 10.0.0.1: icmp_seq=3 ttl=64 time=0.038 ms
64 bytes from 10.0.0.1: icmp_seq=4 ttl=64 time=0.044 ms
^C
— 10.0.0.1 ping statistics —
4 packets transmitted, 4 received, 0% packet loss, time 2999ms
rtt min/avg/max/mdev = 0.038/0.043/0.051/0.005 ms
# 在宿主机器上ping veth1
ping 10.0.0.2
# 输出
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.056 ms
64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.043 ms
64 bytes from 10.0.0.2: icmp_seq=3 ttl=64 time=0.039 ms
64 bytes from 10.0.0.2: icmp_seq=4 ttl=64 time=0.039 ms
^C
— 10.0.0.2 ping statistics —
4 packets transmitted, 4 received, 0% packet loss, time 2999ms
rtt min/avg/max/mdev = 0.039/0.044/0.056/0.008 ms
进行完上面的测试你或许心里会想:“什么鬼?都在同一台机器上当然可以通信啊。”
别着急,我们下面开始学习另一项技术,Network Namespace,想办法把它放在不同的地方。
Network Namespce 网络命名空间
Linux 3.8内核中包括了6种命名空间:
命名空间
描述
Mount(mnt)
隔离挂载点
Process ID(process)
隔离进程ID
Network(net)
隔离网络设备、协议栈、端口等
InterProcess Communication(ipc)
隔离进程间通信
UTS
隔离Hostname和NIS域名
User ID(user)
隔离用户和group ID
其中网络命名空间就是我们今天要学习的内容。
配置网络命名空间
创建两个网络命名空间
ip netns add ns0
ip netns add ns1
将虚拟网卡veth0和veth1分别移动到ns0和ns1网络命名空间中
ip link set veth0 netns ns0
ip link set veth1 netns ns1
此时的网络配置情况如下图,在宿主机器上是看不到veth0和veth1的了
验证网络
测试网络连通性
# 在宿主机器上ping veth0
ping 10.0.0.1
# 输出
PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data.
From 10.0.0.1 icmp_seq=1 Destination Host Unreachable
From 10.0.0.1 icmp_seq=2 Destination Host Unreachable
From 10.0.0.1 icmp_seq=3 Destination Host Unreachable
From 10.0.0.1 icmp_seq=4 Destination Host Unreachable
# 在宿主机器上ping veth1
ping 10.0.0.2
# 输出
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
From 10.0.0.2 icmp_seq=1 Destination Host Unreachable
From 10.0.0.2 icmp_seq=2 Destination Host Unreachable
From 10.0.0.2 icmp_seq=3 Destination Host Unreachable
From 10.0.0.2 icmp_seq=4 Destination Host Unreachable
# 在ns0中ping自己
ip netns exec ns0 ping 10.0.0.1
# 输出
connect: 网络不可达
# 在ns0中ping veth1
ip netns exec ns0 ping 10.0.0.2
# 输出
connect: 网络不可达
却发现无论如何也ping不通,这是为什么呢?让我们来看一下网络命名空间ns0和ns1中的网络信息吧。
查询网络命名空间的网络信息
# 在ns0中查看ip
ip netns exec ns0 ip a
# 输出
1: lo: mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
11: veth0@if10: mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 4a:80:0c:37:b9:de brd ff:ff:ff:ff:ff:ff link-netnsid 1
# 在ns1中查看ip
ip netns exec ns1 ip a
# 输出
1: lo: mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
10: veth1@if11: mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether c2:94:68:ed:45:1d brd ff:ff:ff:ff:ff:ff link-netnsid 0
可以看到不仅本地环回和veth的状态都是DOWN,就连veth的IP信息也没有了,这是因为在不同的网络命名空间中移动虚拟网络接口时会重置虚拟网络接口的状态。
这里使用了ip a命令来查看网卡,因为ifconfig命令不会显示状态为down的网卡
修改veth pair配置
给网络命名空间中的veth配置IP并启动相关网卡
# 配置ns0
ip netns exec ns0 ip addr add 10.0.0.1/24 dev veth0
ip netns exec ns0 ip link set lo up
ip netns exec ns0 ip link set veth0 up
# 配置ns1
ip netns exec ns1 ip addr add 10.0.0.2/24 dev veth1
ip netns exec ns1 ip link set lo up
ip netns exec ns1 ip link set veth1 up
再次验证网络
# 在ns0中ping自己
ip netns exec ns0 ping 10.0.0.1
# 输出
PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data.
64 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=0.033 ms
64 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=0.069 ms
64 bytes from 10.0.0.1: icmp_seq=3 ttl=64 time=0.065 ms
64 bytes from 10.0.0.1: icmp_seq=4 ttl=64 time=0.067 ms
^C
— 10.0.0.1 ping statistics —
4 packets transmitted, 4 received, 0% packet loss, time 3060ms
rtt min/avg/max/mdev = 0.033/0.058/0.069/0.016 ms
# 在ns0中ping veth1
ip netns exec ns0 ping 10.0.0.2
# 输出
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.105 ms
64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.050 ms
64 bytes from 10.0.0.2: icmp_seq=3 ttl=64 time=0.046 ms
64 bytes from 10.0.0.2: icmp_seq=4 ttl=64 time=0.046 ms
^C
— 10.0.0.2 ping statistics —
4 packets transmitted, 4 received, 0% packet loss, time 3000ms
rtt min/avg/max/mdev = 0.046/0.061/0.105/0.026 ms
# 在宿主机器上ping veth1
ping 10.0.0.1
# 输出
PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data.
^C
— 10.0.0.1 ping statistics —
1 packets transmitted, 0 received, 100% packet loss, time 0ms
# 在宿主机器上ping veth1
ping 10.0.0.2
# 输出
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
^C
— 10.0.0.2 ping statistics —
2 packets transmitted, 0 received, 100% packet loss, time 999ms
可以看到在宿主机器无法连通任何一个网络命名空间,证明了网络命名空间的隔离特性。
同时两个网络命名空间是可以通信的,证明了veth pair的连通特性。
看到这里或许你会有这样一个想法,我能否把一个veth设置到netns中,另一个veth保留在宿主机器上呢?
答案是可以的,我们接下来将完成这样的想法。
修改网络配置
将veth0移回宿主机器上,并配置网卡信息
因为veth0在宿主机器上是看不到的,当然也无法操作,因此需要从ns0中操作,默认情况下根网络命令空间的PID是1
# 将veth0移回宿主机器上
ip netns exec ns0 ip link set veth0 netns 1
# 删除ns0
ip netns del ns0
# 启动veth0并配置ip
ip link set veth0 up
ip addr add 10.0.0.1/24 dev veth0
此时的网络配置情况如下图
测试网络连通性
# 在宿主机器上ping veth0
ping 10.0.0.1
# 输出
PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data.
64 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=0.053 ms
64 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=0.039 ms
64 bytes from 10.0.0.1: icmp_seq=3 ttl=64 time=0.034 ms
64 bytes from 10.0.0.1: icmp_seq=4 ttl=64 time=0.038 ms
^C
— 10.0.0.1 ping statistics —
4 packets transmitted, 4 received, 0% packet loss, time 2999ms
rtt min/avg/max/mdev = 0.034/0.041/0.053/0.007 ms
# 在宿主机器上ping veth1
ping 10.0.0.2
# 输出
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.068 ms
64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.048 ms
64 bytes from 10.0.0.2: icmp_seq=3 ttl=64 time=0.045 ms
64 bytes from 10.0.0.2: icmp_seq=4 ttl=64 time=0.040 ms
^C
— 10.0.0.2 ping statistics —
4 packets transmitted, 4 received, 0% packet loss, time 3000ms
rtt min/avg/max/mdev = 0.040/0.050/0.068/0.011 ms
# 在ns1中ping veth0
ip netns exec ns1 ping 10.0.0.1
# 输出
PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data.
64 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=0.071 ms
64 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=0.055 ms
64 bytes from 10.0.0.1: icmp_seq=3 ttl=64 time=0.046 ms
64 bytes from 10.0.0.1: icmp_seq=4 ttl=64 time=0.045 ms
^C
— 10.0.0.1 ping statistics —
4 packets transmitted, 4 received, 0% packet loss, time 2999ms
rtt min/avg/max/mdev = 0.045/0.054/0.071/0.011 ms
使用veth pair我们成功的将宿主机器和网络命名空间的隔离性打破,建立了一个可以互联的网络。这样的场景相当于用一根网线把两个网络设备连接到了一起,而veth pair就是这根”网线“。这种方式也被广泛应用到了docker网络中,后面我们也会讲到如何随心所欲的玩转docker网络。
接下来我们将探讨学习Linux Bridge虚拟网桥。
本文首发 Linux网络设备veth pair和netns 未经允许,不可转载。