概述

veth是Linux的虚拟网卡,和其他虚拟网卡一样,它有两端。不同之处在于veth设备通常成对出现,成对的两个veth设备一端互相连接(类似于一条网线连接两块网卡),另外一端各自连接协议栈。

数据从协议栈流入veth设备后,将从另外一个与之相连的veth设备流出。

veth

案例

veth设备通常用作容器中,实现容器连通外部网络,容器其实就是通过Namespace和CGroup技术实现进程隔离和限制的进程。

下面演示与主机不在同一个net namespace 的进程如何访问外部网络

若在虚拟机中操作,需要设置虚拟机管理软件网卡开启混杂模式,让目的非本机的mac地址通过虚拟机网卡。

方法1:通过bridge实现

网络示意图如下所示

veth-bridge

netnamespace-01

以下操作均在net-namespace01

创建网桥br0,并配置网络

ip link add br0 type bridge

启动网桥

ip link set br0 up

将物理网卡enp0s3加入网桥br0中,此时网络会中断,因为enp0s3 上原有的地址会消失,此时enp0s3的功能相当于一根网线,起到将br0与外界连接的作用。

ip link set enp0s3 master br0

br0相当于交换机和网卡的功能,可以在上面配置ip

ip addr add 192.168.0.183/24 dev br0

配置网关地址,DNS,此处均为临时配置。

$ ip route add default via 192.168.0.1
$ echo 'nameserver 192.168.0.1' >> /etc/resolv.conf

此时可以正常访问外部网络

创建veth设备

ip link add veth1 type veth peer veth0

激活veth0,并加入网桥br0

$ ip link set veth0 up
$ ip link set veth0 master br0

重新打开一个shell窗口,方便在两个namespace中操作

使用unshare命令创建新的net namespace,通过-f 选项fork一个新进程加入新的namespace,新进程运行bash程序

unshare -u -n -f /bin/bash

此时已进入了新的net namespace环境中,修改主机名为namespace-02以便区分

以下操作均在net-namespace02

$ hostname namespace-02
$ exec bash

以下操作均在net-namespace01

veth1加入新的namespace中, 3129namespace 02中bash进程的PID,此时当前namespace中看不到veth1,在namespace02中才能看到。

ip link set veth1 netns 3129

net-namespace02

以下操作均在net-namespace02

激活veth1,并配置默认路由和DNS

$ ip link set veth1 up
$ ip addr add 192.168.0.185/24 dev veth1
$ ip route add default via 192.168.0.1
$ echo 'nameserver 192.168.0.1' >> /etc/resolv.conf

此时namespace02中可以访问外网了。

方法2:iptables SNAT实现

网络连接示意图如下所示

veth-iptables

net-namespace 01

以下操作均在namespace 01

开启ip forward功能,实现路由转发

$ sysctl net.ipv4.ip_forward=1
# 确认是否开启
cat /proc/sys/net/ipv4/ip_forward
1

创建一对veth设备veth0veth1,然后激活veth0,并为其配置IP:172.17.0.1/24

# 创建一对veth设备
$ ip link add veth1 type veth peer veth0
# 激活 veth0
$ ip link set veth0 up
# 配置IP
$ ip addr add 172.17.0.1/24 dev veth0

配置SNAT, 将源地址172.17.0.0/24转换为物理网卡enp0s3的地址

iptables -t nat -A POSTROUTING -s 172.17.0.0/24 -j SNAT --to-source 192.168.0.183

使用unshare创建新的net-namespace 02

重新启动一个shell窗口,执行以下命令

unshare -n -u -f /bin/bash

回到上一个shell窗口,继续执行以下命令

veth1加入到新的net-namespace 02中, 2668为新namespace的bash进程PID

ip link set veth1 netns 2668

net-namespace 02

以下操作在net-namespace 02中完成

修改主机名为namespace-02以便区分,两个namespace的主机名互不影响,这要感谢uts namespace, 我们使用unshare命令的时候使用了-u参数就是实现该隔离功能的。

$ hostname namespace-02
$ exec bash

激活veth1,并配置IP地址、默认路由和DNS

$ ip link set veth1 up
$ ip a a 172.17.0.100/24 dev veth1
$ ip r a default via 172.17.0.1 
$ echo 'nameserver 223.5.5.5' >> /etc/resolv.conf

此时就可以访问外部网络了

$ ping www.baidu.com -c 2

实现类似Docker网络

veth-docker