快捷搜索:  汽车  科技

虚拟专用网络怎么搭建(虚拟网络环境)

虚拟专用网络怎么搭建(虚拟网络环境)#sudo ip addr add 192.168.4.3/24 dev veth0 #sudo ip addr add 192.168.4.2/24 dev veth1 #sudo ip link set veth0 up #sudo ip link set veth1 up # ip addr show 6: veth1@veth0: <BROADCAST MULTICAST UP LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether 42:7b:d8:e5:47:82 brd ff:ff:ff:ff:ff:ff inet 192.168.4.2/24 scope global veth1 valid_lft forever preferre

一 前言

本来这几天研究eBPF的xdp的,虽然阅读了不少资料,但是测试代码仍然有问题,所以耽误了,在测试过程中发现了虚拟网络环境,又是自己没有接触过的,所以研究下,挺有意思的,写了篇文章分享下。

简单来说,就是构建一套虚拟的网络环境。

二 交叉线和veth

如果玩计算机比较早的朋友,如果没有路由器,集线器这些通讯设备,我们两个计算机想连接打个CS啥的,也是有一种办法的,就是采用双绞线直连,我记得买这种线子的时候,一定要选择交叉线(只是线的顺序不一样做网线的时候做下),才可以计算机对计算机,即同类设备连接,如果是计算机连集线器啥的,用的是直连线,现在用直连线计算机据说也可以适配了,目前没用过。

虚拟专用网络怎么搭建(虚拟网络环境)(1)

我们在一个计算机中,也可以虚拟出来类似交叉线的东东,veth即表示两个类似通过交叉线互联的虚拟网卡。

2.1 veth使用

简单实用ip命令创建veth,这个如同上面的交叉线,是两个虚拟网卡做成一对,可以配置同一个网段的ip,也可以互联通信。 一般用于不同的网络空间,通过veth连着两个协议栈 更好地理解可以认为是bash中的管道,从一端输入另一端输出。

ip link add veth0 type veth peer name veth1

把参数用中括号括起来方便查看如下:

ip link add [veth0] type veth peer name [veth1]

veth0和veth1是虚拟两个网卡名字,结果通过命令查看:

IP link ... 6: veth1@veth0: <BROADCAST MULTICAST M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 42:7b:d8:e5:47:82 brd ff:ff:ff:ff:ff:ff 7: veth0@veth1: <BROADCAST MULTICAST M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 0a:21:f4:08:f9:92 brd ff:ff:ff:ff:ff:ff

可以看到没设置ip,也没有启动,设置ip,启动下看看效果,如下命令:

#sudo ip addr add 192.168.4.3/24 dev veth0 #sudo ip addr add 192.168.4.2/24 dev veth1 #sudo ip link set veth0 up #sudo ip link set veth1 up # ip addr show 6: veth1@veth0: <BROADCAST MULTICAST UP LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether 42:7b:d8:e5:47:82 brd ff:ff:ff:ff:ff:ff inet 192.168.4.2/24 scope global veth1 valid_lft forever preferred_lft forever inet6 fe80::407b:d8ff:fee5:4782/64 scope link valid_lft forever preferred_lft forever 7: veth0@veth1: <BROADCAST MULTICAST UP LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether 0a:21:f4:08:f9:92 brd ff:ff:ff:ff:ff:ff inet 192.168.4.3/24 scope global veth0 valid_lft forever preferred_lft forever inet6 fe80::821:f4ff:fe08:f992/64 scope link valid_lft forever preferred_lft forever

可以看到ip已经启动,ip也设置好了。 现在的网络情况是这样的 如下图:

虚拟专用网络怎么搭建(虚拟网络环境)(2)

命令验证如下:

root@ubuntu-lab:~# ping 192.168.4.2 -I lo ping: Warning: source address might be selected on device other than: lo PING 192.168.4.2 (192.168.4.2) from 192.168.31.198 lo: 56(84) bytes of data. 64 bytes from 192.168.4.2: icmp_seq=1 ttl=64 time=0.051 ms ^C --- 192.168.4.2 ping statistics --- 1 packets transmitted 1 received 0% packet loss time 0ms rtt min/avg/max/mdev = 0.051/0.051/0.051/0.000 ms root@ubuntu-lab:~# ping 192.168.4.3 -I lo ping: Warning: source address might be selected on device other than: lo PING 192.168.4.3 (192.168.4.3) from 192.168.31.198 lo: 56(84) bytes of data. 64 bytes from 192.168.4.3: icmp_seq=1 ttl=64 time=0.076 ms 64 bytes from 192.168.4.3: icmp_seq=2 ttl=64 time=0.155 ms ^C --- 192.168.4.3 ping statistics --- 2 packets transmitted 2 received 0% packet loss time 1017ms rtt min/avg/max/mdev = 0.076/0.115/0.155/0.039 ms root@ubuntu-lab:~# ping 192.168.4.3 -I eth1 ping: SO_BINDTODEVICE eth1: No such device root@ubuntu-lab:~# ping 192.168.4.3 -I veth1 PING 192.168.4.3 (192.168.4.3) from 192.168.4.2 veth1: 56(84) bytes of data. ^C --- 192.168.4.3 ping statistics --- 3 packets transmitted 0 received 100% packet loss time 2033ms root@ubuntu-lab:~# ping 192.168.4.2 -I veth0 PING 192.168.4.2 (192.168.4.2) from 192.168.4.3 veth0: 56(84) bytes of data. ^C

在用 ping 192.168.4.3 -I lo 命令我们对veth0 抓包也没有抓到ping包,说明是走的lo回环。

root@ubuntu-lab:/home/miao/xdp-test# echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter root@ubuntu-lab:/home/miao/xdp-test# echo 0 > /proc/sys/net/ipv4/conf/veth0/rp_filter root@ubuntu-lab:/home/miao/xdp-test# echo 0 > proc/sys/net/ipv4/conf/veth1/rp_filter root@ubuntu-lab:/home/miao/xdp-test# echo 1 > /proc/sys/net/ipv4/conf/veth1/accept_local root@ubuntu-lab:/home/miao/xdp-test# echo 1 > /proc/sys/net/ipv4/conf/veth0/accept_local

rp_filter (Reverse Path Filtering)参数定义了网卡对接收到的数据包进行反向路由验证的规则。 1(默认值)表示源IP必须是路由可达的,同时入口接口恰好是路由表查到的接口; 2 表示源IP必须是路由可达的,但放松为任意接口可达即可; 0 表示不检查源IP

所谓反向路由校验,就是在一个网卡收到数据包后,把源地址和目标地址对调后查找路由出口,从而得到反身后路由出口。然后根据反向路由出口进行过滤。 当rp_filter的值为1时,要求反向路由的出口必须与数据包的入口网卡是同一块,否则就会丢弃数据包。 当rp_filter的值为2时,要求反向路由必须是可达的,如果反路由不可达,则会丢弃数据包。

这是因为Linux还有一个检测源IP地址的机制,若收到的IP报文源IP与本机上某一个IP相同,那么内核默认丢弃这个报文。这其实也很好理解,正常情况下,如果收到一个IP报文的源地址属于自己,那么可能这个IP报文是伪造的。但也有一些特殊的场景可能用到,例如LVS机器的DR模式或者隧道模式,恰好LVS机器又处在响应的路径里,此时响应源IP是一个VIP,恰好与LVS机器上环回接口配置的一致。 accept_local可以改变默认的行为,把它设为1则接受源IP是本机中的IP的报文通过。

其实ping下不返回,则抓下包:

root@ubuntu-lab:/home/miao/xdp-test# ping 192.168.4.2 -I veth0 PING 192.168.4.2 (192.168.4.2) from 192.168.4.3 veth0: 56(84) bytes of data. root@ubuntu-lab:/home/miao/ebpfkit-master# tcpdump -i veth1 -vv -n tcpdump: listening on veth1 link-type EN10MB (Ethernet) snapshot length 262144 bytes 06:41:20.542005 IP (tos 0x0 ttl 64 id 11454 offset 0 flags [DF] proto ICMP (1) length 84) 192.168.4.3 > 192.168.4.2: ICMP echo request id 31 seq 941 length 64 06:41:21.565565 IP (tos 0x0 ttl 64 id 11710 offset 0 flags [DF] proto ICMP (1) length 84) 192.168.4.3 > 192.168.4.2: ICMP echo request id 31 seq 942 length 64 # 返回的报文是从lo过来的,所以ping没有返回 root@ubuntu-lab:/home/miao/ebpfkit-master# tcpdump -i lo -vv -n tcpdump: listening on lo link-type EN10MB (Ethernet) snapshot length 262144 bytes 11:35:42.893121 IP (tos 0x0 ttl 64 id 3593 offset 0 flags [none] proto ICMP (1) length 84) 192.168.4.2 > 192.168.4.3: ICMP echo reply id 50 seq 325 length 64 11:35:43.917182 IP (tos 0x0 ttl 64 id 3726 offset 0 flags [none] proto ICMP (1) length 84) 192.168.4.2 > 192.168.4.3: ICMP echo reply id 50 seq 326 length 64 11:35:44.942339 IP (tos 0x0 ttl 64 id 3738 offset 0 flags [none] proto ICMP (1) length 84) 192.168.4.2 > 192.168.4.3: ICMP echo reply id 50 seq 327 length 64

其实看到上面的抓包,veth1 网卡收到包了但是返回从lo返回,返回的时候没办法指定网卡。

2.2 加路由让ping返回走特定网卡

添加路由信息:

root@ubuntu-lab:/home/miao/ebpfkit-master# ip rule add pref 1000 tab local root@ubuntu-lab:/home/miao/ebpfkit-master# ip rule add fwmark 100 pref 100 tab 100 # 目的是为了路由信息提到local之前 root@ubuntu-lab:/home/miao/ebpfkit-master# ip rule add pref 1000 tab local root@ubuntu-lab:/home/miao/ebpfkit-master# ip rule del pref 0 tab local root@ubuntu-lab:/home/miao/ebpfkit-master# ip route add 192.168.4.2/32 dev veth0 src 192.168.4.3 tab 100 root@ubuntu-lab:/home/miao/ebpfkit-master# ip route add 192.168.4.3/32 dev veth1 src 192.168.4.2 tab 100 # 给出去报文加标识 root@ubuntu-lab:/home/miao/xdp-test# iptables -t mangle -A OUTPUT -d 192.168.4.2/32 -j MARK --set-mark 100

然后还是不行,检查了很多配置,检查一天还是没ping通,查看路由:

root@ubuntu-lab:~# ip route get 192.168.4.2 local 192.168.4.2 dev lo table local src 192.168.4.2 uid 0 cache <local> root@ubuntu-lab:~# ip route get 192.168.4.3 local 192.168.4.3 dev lo table local src 192.168.4.3 uid 0 cache <local>

通过配置来看,走的仍然是lo,用的是缓存,但是没有办法清理lo路由,因为:

root@ubuntu-lab:~# ip route ls tab 100 192.168.4.2 dev veth0 scope link src 192.168.4.3 192.168.4.3 dev veth1 scope link src 192.168.4.2 root@ubuntu-lab:~# ip route ls tab 1000 Error: ipv4: FIB table does not exist. Dump terminated

目前还没有找到办法清理。但是veth更多的是用来转发,比如我们发到veth0的数据可以自动转发到veth1,反之亦然。

三 交换机“bridge”

上面聊的veth,每队通信都要通过路由配置来做,非常麻烦,这个在实际使用如果虚拟网络环境太多,路由都搞得很复杂不值得。

现实中,上大学宿舍多人组网,要么是集线器,要么是交换机,同样在网络环境中,我们也可以通过一个软件实现brige,然后多个虚拟网卡连在一起,借助纯软件实现通信。 Docker 有种网络模式就是这样通信的,如下图:

虚拟专用网络怎么搭建(虚拟网络环境)(3)

清理下环境,重新试验:

#删除veth,删除veth0,veth1自动也删除了。 root@ubuntu-lab:/home/miao/ebpfkit-master# ip link del veth0 #清理路由配置 #ip route del 192.168.4.2/32 dev veth0 src 192.168.4.3 tab 100 #ip route del 192.168.4.3/32 dev veth1 src 192.168.4.2 tab 100 root@ubuntu-lab:/home/miao/ebpfkit-master# ip rule del fwmark 100 3.1 新建虚拟网络环境

Network namespace是linux内核提供的进行网络隔离的功能,每个网络空间都有自己的网络协议栈,路由表,lo等。Docker的网络环境就是通过Network namespace进行网络隔离的。准备搭建的环境如下:

虚拟专用网络怎么搭建(虚拟网络环境)(4)

我们新建了两个不同的网络空间,设置不同的网络段,目标是通过bridge来相互ping通,达到网络互联的目的,再多容器都可以通过连接到bridge来达到相互通信的目的。

建立虚拟网络空间

root@ubuntu-lab:/home/miao/ebpfkit-master# ip netns add ns1 root@ubuntu-lab:/home/miao/ebpfkit-master# ip netns add ns2 root@ubuntu-lab:/home/miao/ebpfkit-master# ip netns ns2 ns1

创建veth对

root@ubuntu-lab:/home/miao/ebpfkit-master# ip link add veth1 type veth peer name veth1_p root@ubuntu-lab:/home/miao/ebpfkit-master# ip link set veth1 netns ns1 root@ubuntu-lab:/home/miao/ebpfkit-master# ip link add veth2 type veth peer name veth2_p root@ubuntu-lab:/home/miao/ebpfkit-master# ip link set veth2 netns ns2

配置ip和启动

ip netns exec ns1 ip addr add 192.168.5.101/24 dev veth1 ip netns exec ns1 ip link set veth1 up ip netns exec ns2 ip addr add 192.168.5.102/24 dev veth2 ip netns exec ns2 ip link set veth2 up

查看配置结果:

root@ubuntu-lab:/home/miao/ebpfkit-master# ip netns exec ns1 ip link list 1: lo: <loopback> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 9: veth1@if8: <NO-CARRIER BROADCAST MULTICAST UP> mtu 1500 qdisc noqueue state LOWERLAYERDOWN mode DEFAULT group default qlen 1000 link/ether 42:7b:d8:e5:47:82 brd ff:ff:ff:ff:ff:ff link-netnsid 0 root@ubuntu-lab:/home/miao/ebpfkit-master# ip netns exec ns2 ip link list 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 11: veth2@if10: <NO-CARRIER BROADCAST MULTICAST UP> mtu 1500 qdisc noqueue state LOWERLAYERDOWN mode DEFAULT group default qlen 1000 link/ether ca:18:9d:4c:8b:bc brd ff:ff:ff:ff:ff:ff link-netnsid 0 root@ubuntu-lab:/home/miao/ebpfkit-master# ip netns exec ns1 ifconfig veth1: flags=4099<UP BROADCAST MULTICAST> mtu 1500 inet 192.168.5.101 netmask 255.255.255.0 broadcast 0.0.0.0 ether 42:7b:d8:e5:47:82 txqueuelen 1000 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 root@ubuntu-lab:/home/miao/ebpfkit-master# ip netns exec ns2 ifconfig veth2: flags=4099<UP BROADCAST MULTICAST> mtu 1500 inet 192.168.5.102 netmask 255.255.255.0 broadcast 0.0.0.0 ether ca:18:9d:4c:8b:bc txqueuelen 1000 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 3.2 创建虚拟bridge,虚拟网卡连接bridge

命令如下:

#创建bridge #brctl addbr br0 #将veth一端连接到bridge ip link set dev veth1_p master br0 ip link set dev veth2_p master br0 #设置bridge的ip ip addr add 192.168.5.1/24 dev br0

bridge和veth的启动:

ip link set veth1_p up ip link set veth2_p up ip link set br0 up

查看网络信息:

root@ubuntu-lab:/home/miao/ebpfkit-master# brctl show bridge name bridge id STP enabled interfaces br0 8000.d246bc47bc05 no veth1_p

配置好后的ip示意图:

虚拟专用网络怎么搭建(虚拟网络环境)(5)

搞定之后,利用ping测试下:

root@ubuntu-lab:/home/miao# ip netns exec ns1 ping 192.168.5.102 PING 192.168.5.102 (192.168.5.102) 56(84) bytes of data. 64 bytes from 192.168.5.102: icmp_seq=1 ttl=64 time=0.050 ms 64 bytes from 192.168.5.102: icmp_seq=2 ttl=64 time=0.085 ms 64 bytes from 192.168.5.102: icmp_seq=3 ttl=64 time=0.085 ms root@ubuntu-lab:/home/miao# ip netns exec ns2 ping 192.168.5.101 PING 192.168.5.101 (192.168.5.101) 56(84) bytes of data. 64 bytes from 192.168.5.101: icmp_seq=1 ttl=64 time=0.106 ms 64 bytes from 192.168.5.101: icmp_seq=2 ttl=64 time=0.093 ms 64 bytes from 192.168.5.101: icmp_seq=3 ttl=64 time=0.058 ms

刚开始也是不通的,后来发现原因 bridge 开启了iptables功能,导致所有经过br0的网络包都受到iptables的限制,docker为了安全性,将iptables的filter 表的FORWARD链默认设置成drop了,所以导致了ping的包被drop导致的。

关键是这条路由啊:

root@ubuntu-lab:/home/miao# iptables -A FORWARD -i br0 -j ACCEPT 3.3 换换网段测试看看

虽然测试的时候用的ip是属于同一个网段,但是 br0的ip设置在ping的时候是没有用的,更改下试试

root@ubuntu-lab:/home/miao# ip addr del 192.168.5.1/24 dev br0 root@ubuntu-lab:/home/miao# ip addr add 192.168.6.1/24 dev br0

ping测试的效果不受到影响:

root@ubuntu-lab:/home/miao# ip netns exec ns1 ping 192.168.5.102 PING 192.168.5.102 (192.168.5.102) 56(84) bytes of data. 64 bytes from 192.168.5.102: icmp_seq=1 ttl=64 time=0.092 ms 64 bytes from 192.168.5.102: icmp_seq=2 ttl=64 time=0.095 ms ^C --- 192.168.5.102 ping statistics --- 2 packets transmitted 2 received 0% packet loss time 1038ms rtt min/avg/max/mdev = 0.092/0.093/0.095/0.001 ms root@ubuntu-lab:/home/miao# ip netns exec ns2 ping 192.168.5.101 PING 192.168.5.101 (192.168.5.101) 56(84) bytes of data. 64 bytes from 192.168.5.101: icmp_seq=1 ttl=64 time=0.090 ms 64 bytes from 192.168.5.101: icmp_seq=2 ttl=64 time=0.063 ms ^C --- 192.168.5.101 ping statistics --- 2 packets transmitted 2 received 0% packet loss time 1012ms rtt min/avg/max/mdev = 0.063/0.076/0.090/0.013 ms root@ubuntu-lab:/home/miao#

虽然每个网络空间的里面的br0的ip不对了,但是仍然不受到影响:

root@ubuntu-lab:/home/miao# ip -n ns1 route default via 192.168.5.1 dev veth1 192.168.5.0/24 dev veth1 scope link root@ubuntu-lab:/home/miao# ip -n ns2 route default via 192.168.5.1 dev veth2 192.168.5.0/24 dev veth2 scope link

继续换下,让两个网络的ip属于不同网段玩玩。

root@ubuntu-lab:/home/miao# ip netns exec ns2 ip addr del 192.168.5.102/24 dev veth2 root@ubuntu-lab:/home/miao# ip netns exec ns2 ip addr add 10.25.5.102/24 dev veth2 root@ubuntu-lab:/home/miao# ip netns exec ns2 ip route 10.25.5.0/24 dev veth2 proto kernel scope link src 10.25.5.102 root@ubuntu-lab:/home/miao# ip -n ns2 route add 192.168.5.0/24 dev veth2 root@ubuntu-lab:/home/miao# ip -n ns1 route add 10.25.5.0/24 dev veth1 root@ubuntu-lab:/home/miao# ip netns exec ns1 ip route 10.25.5.0/24 dev veth1 scope link 192.168.5.0/24 dev veth1 scope link root@ubuntu-lab:/home/miao# ip netns exec ns2 ip route 10.25.5.0/24 dev veth2 proto kernel scope link src 10.25.5.102 192.168.5.0/24 dev veth2 scope link root@ubuntu-lab:/home/miao# ip addr 12: br0: <BROADCAST MULTICAST UP LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether d2:46:bc:47:bc:05 brd ff:ff:ff:ff:ff:ff inet 192.168.6.1/24 scope global br0 root@ubuntu-lab:/home/miao# ip netns exec ns1 ping 10.25.5.102 PING 10.25.5.102 (10.25.5.102) 56(84) bytes of data. 64 bytes from 10.25.5.102: icmp_seq=1 ttl=64 time=0.089 ms 64 bytes from 10.25.5.102: icmp_seq=2 ttl=64 time=0.103 ms 64 bytes from 10.25.5.102: icmp_seq=3 ttl=64 time=0.089 ms

哇竟然真的还是通的,br0,veth0,veth1分别设置了三个网段的地址,配置好路由后仍然不影响他们之间的通讯的。 虚拟网络空间的命令执行有些类似于docker,看看下面的命令 :

root@ubuntu-lab:/home/miao# ip netns exec ns1 /bin/bash root@ubuntu-lab:/home/miao# ip addr 1: lo: <LOOPBACK UP LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 9: veth1@if8: <BROADCAST MULTICAST UP LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether 42:7b:d8:e5:47:82 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 192.168.5.101/24 scope global veth1 valid_lft forever preferred_lft forever inet6 fe80::407b:d8ff:fee5:4782/64 scope link valid_lft forever preferred_lft forever root@ubuntu-lab:/home/miao# exit exit

可以进入网络空间,也可以像上面那样,直接在网络空间执行命令。 为了区分不同的网络空间提示符,可以在执行exec命令的时候修改下:

oot@ubuntu-lab:/home/miao# ip netns exec ns1 /bin/bash --rcfile <(echo "PS1=\"namespace ns1> \"") namespace ns1> ip addr 1: lo: <LOOPBACK UP LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 9: veth1@if8: <BROADCAST MULTICAST UP LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether 42:7b:d8:e5:47:82 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 192.168.5.101/24 scope global veth1 valid_lft forever preferred_lft forever inet6 fe80::407b:d8ff:fee5:4782/64 scope link valid_lft forever preferred_lft forever namespace ns1> exit exit

猜您喜欢: