bridge设备
什么是 bridge
bridge 是一个虚拟网络设备,可以配置 IP、MAC 地址等,bridge 是一个虚拟交换机,和物理交换机有类似的功能。
普通的网络设备两端,数据会从一端进入然后从另一端出去,如物理网卡从外部网络中收到的数据会转发给内核协议栈,而从协议栈过来的数据会转发到外部的物理网络中。
bridge 不同,bridge 有多个端口,数据库可以从任意端口进入,进入后从哪个端口出去和物理交换机原理差不多,需要查看 MAC 地址。
创建 bridge
创建初始的 bridge 网桥如下:
dev@debian:~$ sudo ip link add name br0 type bridge
dev@debian:~$ sudo ip link set br0 up
当刚创建一个 bridge 时,它是一个独立的网络设备,只有一个端口连接着协议栈,另一端空缺,这样的网桥没有任何功能:
+----------------------------------------------------------------+
| |
| +------------------------------------------------+ |
| | Newwork Protocol Stack | |
| +------------------------------------------------+ |
| ↑ ↑ |
|..............|................................|................|
| ↓ ↓ |
| +----------+ +------------+ |
| | eth0 | | br0 | |
| +----------+ +------------+ |
| 192.168.3.21 ↑ |
| | |
| | |
+--------------|-------------------------------------------------+
↓
Physical Network
连接 bridge 和 veth 设备
创建一对 veth 设备并配置上 IP地址:
dev@debian:~$ sudo ip link add veth0 type veth peer name veth1
dev@debian:~$ sudo ip addr add 192.168.3.101/24 dev veth0
dev@debian:~$ sudo ip addr add 192.168.3.102/24 dev veth1
dev@debian:~$ sudo ip link set veth0 up
dev@debian:~$ sudo ip link set veth1 up
将 veth0 连接上 br0 网桥:
dev@debian:~$ sudo ip link set dev veth0 master br0
#通过bridge link命令可以看到br0上连接了哪些设备
dev@debian:~$ sudo bridge link
6: veth0 state UP : <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br0 state forwarding priority 32 cost 2
建立网桥连接后网络如下:
+----------------------------------------------------------------+
| |
| +------------------------------------------------+ |
| | Newwork Protocol Stack | |
| +------------------------------------------------+ |
| ↑ ↑ | ↑ |
|............|............|..............|............|..........|
| ↓ ↓ ↓ ↓ |
| +------+ +--------+ +-------+ +-------+ |
| | .3.21| | | | .3.101| | .3.102| |
| +------+ +--------+ +-------+ +-------+ |
| | eth0 | | br0 |<--->| veth0 | | veth1 | |
| +------+ +--------+ +-------+ +-------+ |
| ↑ ↑ ↑ |
| | | | |
| | +------------+ |
| | |
+------------|---------------------------------------------------+
↓
Physical Network
br0
和 veth0
连接后变化如下:
网桥 br0
和 veth0 之间建立了连接,并且是双向通道;- 协议栈和 veth0 之间变成了单向通道,协议栈能发送数据给 br0,但是 veth0 从外面接收到的数据不会转发给协议栈;
- br0 的 MAC地址变成了 veth0 的 MAC地址;
也就是说 br0 在网络协议栈和 veth0 之间做了些动作,将 veth0 原本要发送给协议栈的数据给拦截了,全部转发给 bridge 了,同时 bridge 可以向 veth0 发送数据。
测试发现 veth0 加入 bridge 后就无法 ping 通 veth1 了,抓包后结果如下:
#由于veth0的arp缓存里面没有veth1的mac地址,所以ping之前先发arp请求
#从veth1上抓包来看,veth1收到了arp请求,并且返回了应答
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
21:43:48.353509 ARP, Request who-has 192.168.3.102 tell 192.168.3.101, length 28
21:43:48.353518 ARP, Reply 192.168.3.102 is-at 26:58:a2:57:37:e9, length 28
#从veth0上抓包来看,数据包也发出去了,并且也收到了返回
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
21:44:09.775392 ARP, Request who-has 192.168.3.102 tell 192.168.3.101, length 28
21:44:09.775400 ARP, Reply 192.168.3.102 is-at 26:58:a2:57:37:e9, length 28
#再看br0上的数据包,发现只有应答
dev@debian:~$ sudo tcpdump -n -i br0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on br0, link-type EN10MB (Ethernet), capture size 262144 bytes
21:45:48.225459 ARP, Reply 192.168.3.102 is-at 26:58:a2:57:37:e9, length 28
根据上述分析可以发现,数据包由 veth1 返回给 veth0 后并没有发送到网络协议栈上,而是交给了 bridge,因此协议栈无法得到 veth1 的 MAC 地址,导致通信失败。
配置 bridge 的 IP 地址
上面测试发现分配给 veth0 的 IP地址并没有意义,返回的结果数据包并不会转发到网络协议栈上,这里将 veth0 的 IP 地址配置给 bridge。
dev@debian:~$ sudo ip addr del 192.168.3.101/24 dev veth0
dev@debian:~$ sudo ip addr add 192.168.3.101/24 dev br0
配置后网络结构如下:
+----------------------------------------------------------------+
| |
| +------------------------------------------------+ |
| | Newwork Protocol Stack | |
| +------------------------------------------------+ |
| ↑ ↑ ↑ |
|............|............|...........................|..........|
| ↓ ↓ ↓ |
| +------+ +--------+ +-------+ +-------+ |
| | .3.21| | .3.101 | | | | .3.102| |
| +------+ +--------+ +-------+ +-------+ |
| | eth0 | | br0 |<--->| veth0 | | veth1 | |
| +------+ +--------+ +-------+ +-------+ |
| ↑ ↑ ↑ |
| | | | |
| | +------------+ |
| | |
+------------|---------------------------------------------------+
↓
Physical Network
这里 veth0 就相当于一根网线,这里 veth0 和网络协议栈之间虽然还有联系,但是由于 veth0 并没有配置 IP 地址,所以协议栈路由时不会将数据包转发给 veth0。
尝试 ping veth1
发现成功,但是 ping 网关还是会失败,因为此时 bridge 中只有两个网络设备:192.168.3.101
、192.168.3.102
。bridge 并不知道网关对应的 IP 地址。
将物理网卡添加到 bridge
添加 eth0 到 br0 上:
dev@debian:~$ sudo ip link set dev eth0 master br0
dev@debian:~$ sudo bridge link
2: eth0 state UP : <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br0 state forwarding priority 32 cost 4
6: veth0 state UP : <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br0 state forwarding priority 32 cost 2
bridge 作为虚拟设备不区分接入进来的是物理设备还是虚拟设备,所以当 eth0 加入 br0 后,eth0 就可以看成一根网线。此时通过 eth0 来 ping 网关会失败,但由于 br0 通过 eth0 连接上了外部网络,所以连接在 br0 上的设备都能够 ping 通网关,这里连接上的设备只有 veth1、br0,veth1 是通过 veth0 这根网线连接的,br0 可以理解为有自带的一块网卡。
物理网卡 eth0 作用和网线一样,所以移除它上面配置的 IP 地址:
#在本人的测试机器上,由于eth0上有IP,
#访问192.168.3.0/24网段时,会优先选择eth0
dev@debian:~$ sudo route -v
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default 192.168.3.1 0.0.0.0 UG 0 0 0 eth0
link-local * 255.255.0.0 U 1000 0 0 eth0
192.168.3.0 * 255.255.255.0 U 0 0 0 eth0
192.168.3.0 * 255.255.255.0 U 0 0 0 veth1
192.168.3.0 * 255.255.255.0 U 0 0 0 br0
#由于eth0已结接入了br0,所有它收到的数据包都会转发给br0,
#于是协议栈收不到arp应答包,导致ping失败
dev@debian:~$ ping -c 1 192.168.3.1
PING 192.168.3.1 (192.168.3.1) 56(84) bytes of data.
From 192.168.3.21 icmp_seq=1 Destination Host Unreachable
--- 192.168.3.1 ping statistics ---
1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms
#将eth0上的IP删除掉
dev@debian:~$ sudo ip addr del 192.168.3.21/24 dev eth0
#再ping一次,成功
dev@debian:~$ ping -c 1 192.168.3.1
PING 192.168.3.1 (192.168.3.1) 56(84) bytes of data.
64 bytes from 192.168.3.1: icmp_seq=1 ttl=64 time=3.91 ms
--- 192.168.3.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 3.916/3.916/3.916/0.000 ms
#这是因为eth0没有IP之后,路由表里面就没有它了,于是数据包会从veth1出去
dev@debian:~$ sudo route -v
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
192.168.3.0 * 255.255.255.0 U 0 0 0 veth1
192.168.3.0 * 255.255.255.0 U 0 0 0 br0
#从这里也可以看出,由于原来的默认路由走的是eth0,所以当eth0的IP被删除之后,
#默认路由不见了,想要连接192.168.3.0/24以外的网段的话,需要手动将默认网关加回来
#添加默认网关,然后再ping外网成功
dev@debian:~$ sudo ip route add default via 192.168.3.1
dev@debian:~$ ping -c 1 baidu.com
PING baidu.com (111.13.101.208) 56(84) bytes of data.
64 bytes from 111.13.101.208: icmp_seq=1 ttl=51 time=30.6 ms
--- baidu.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 30.690/30.690/30.690/0.000 ms
所有上述操作执行完毕后网络结构如下:
+----------------------------------------------------------------+
| |
| +------------------------------------------------+ |
| | Newwork Protocol Stack | |
| +------------------------------------------------+ |
| ↑ ↑ |
|.........................|...........................|..........|
| ↓ ↓ |
| +------+ +--------+ +-------+ +-------+ |
| | | | .3.101 | | | | .3.102| |
| +------+ +--------+ +-------+ +-------+ |
| | eth0 |<--->| br0 |<--->| veth0 | | veth1 | |
| +------+ +--------+ +-------+ +-------+ |
| ↑ ↑ ↑ |
| | | | |
| | +------------+ |
| | |
+------------|---------------------------------------------------+
↓
Physical Network
bridge 应用场景
虚拟机
虚拟机通过 tun/tap
、bridge
等虚拟网络设备,将虚拟机内的网卡同 br0
连接起来,这样就和真实交换机一样了,虚拟机发送出去的数据包先到达 br0
,然后由 br0
转发到物理网卡 eth0
后发送到外部网络,这样虚拟机中的数据包不需要经过主机的网络协议栈,效率更高。
+----------------------------------------------------------------+-----------------------------------------+-----------------------------------------+
| Host | VirtualMachine1 | VirtualMachine2 |
| | | |
| +------------------------------------------------+ | +-------------------------+ | +-------------------------+ |
| | Newwork Protocol Stack | | | Newwork Protocol Stack | | | Newwork Protocol Stack | |
| +------------------------------------------------+ | +-------------------------+ | +-------------------------+ |
| ↑ | ↑ | ↑ |
|..........................|.....................................|...................|.....................|....................|....................|
| ↓ | ↓ | ↓ |
| +--------+ | +-------+ | +-------+ |
| | .3.101 | | | .3.102| | | .3.103| |
| +------+ +--------+ +-------+ | +-------+ | +-------+ |
| | eth0 |<--->| br0 |<--->|tun/tap| | | eth0 | | | eth0 | |
| +------+ +--------+ +-------+ | +-------+ | +-------+ |
| ↑ ↑ ↑ | ↑ | ↑ |
| | | +-------------------------------------------+ | | |
| | ↓ | | | |
| | +-------+ | | | |
| | |tun/tap| | | | |
| | +-------+ | | | |
| | ↑ | | | |
| | +-------------------------------------------------------------------------------|--------------------+ |
| | | | |
| | | | |
| | | | |
+------------|---------------------------------------------------+-----------------------------------------+-----------------------------------------+
↓
Physical Network (192.168.3.0/24)
docker
docker 容器运行在自己单独的 network namespace
中,所以有单独的网络协议栈,采取如下方式和外部通信:
+----------------------------------------------------------------+-----------------------------------------+-----------------------------------------+
| Host | Container 1 | Container 2 |
| | | |
| +------------------------------------------------+ | +-------------------------+ | +-------------------------+ |
| | Newwork Protocol Stack | | | Newwork Protocol Stack | | | Newwork Protocol Stack | |
| +------------------------------------------------+ | +-------------------------+ | +-------------------------+ |
| ↑ ↑ | ↑ | ↑ |
|............|.............|.....................................|...................|.....................|....................|....................|
| ↓ ↓ | ↓ | ↓ |
| +------+ +--------+ | +-------+ | +-------+ |
| |.3.101| | .9.1 | | | .9.2 | | | .9.3 | |
| +------+ +--------+ +-------+ | +-------+ | +-------+ |
| | eth0 | | br0 |<--->| veth | | | eth0 | | | eth0 | |
| +------+ +--------+ +-------+ | +-------+ | +-------+ |
| ↑ ↑ ↑ | ↑ | ↑ |
| | | +-------------------------------------------+ | | |
| | ↓ | | | |
| | +-------+ | | | |
| | | veth | | | | |
| | +-------+ | | | |
| | ↑ | | | |
| | +-------------------------------------------------------------------------------|--------------------+ |
| | | | |
| | | | |
| | | | |
+------------|---------------------------------------------------+-----------------------------------------+-----------------------------------------+
↓
Physical Network (192.168.3.0/24)
可以发现容器中配置网关为 .9.1
,从容器发送出去的数据包优先到达 br0
,然后转发给主机协议栈,主机协议栈内对内网IP转换为外网IP,数据包最终通过物理网卡 eth0
转发出去。这种方案的缺点在于容器内的数据包需要转发到主机的网络协议栈,并做 NAT 转换,性能会稍差些;但是优点在于内网IP,数据包统一由 eth0 转发,安全性更高。