接上篇网络虚拟化之虚拟网卡技术veth再来看看虚拟交换机技术Linux Bridge。
几个核心点:
1.veth只能成对出现,多对多就需要一个交换机
2.Linux Bridge覆盖物理交换机所有功能
3.Linux Bridge比物理交换机多一个转发本机协议栈的数据包
4.单IP的主机上多个容器可以通过Bridge与外部通讯,此时主机扮演路由器角色实现SNAT和DNAT转换
有了虚拟网卡,很自然也会联想到让网卡接入到交换机里,实现多个容器间的相互连接。Linux Bridge 便是 Linux 系统下的虚拟化交换机,虽然它以“网桥”(Bridge)而不是“交换机”(Switch)为名,然而使用过程中,你会发现 Linux Bridge 的目的看起来像交换机,功能使用起来像交换机、程序实现起来也像交换机,实际就是一台虚拟交换机。Linux Bridge 是在 Linux Kernel 2.2 版本开始提供的二层转发工具,由 brctl 命令创建和管理。Linux Bridge 创建以后,便能够接入任何位于二层的网络设备,无论是真实的物理设备(譬如 eth0)抑或是虚拟的设备(譬如 veth 或者 tap)都能与 Linux Bridge 配合工作。
如果数据包的目的 MAC 地址为网桥本身,并且网桥有设置了 IP 地址的话,那该数据包即被认为是收到发往创建网桥那台主机的数据包,此数据包将不会转发到任何设备,而是直接交给上层(三层)协议栈去处理。通过这种方式可以实现连接到Linux bridge的设备与外部通信,主机扮演路由器角色。
1.用iproute2创建一个bridge:
sudo ip link add name mbr0 type bridge
sudo ip link set mbr0 up
ifconfig可以看到这个设备
ifconfig
br0: flags=4163
inet6 fe80::2c0a:ceff:fe21:d304 prefixlen 64 scopeid 0x20
ether 2e:0a:ce:21:d3:04 txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 8 bytes 656 (656.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
新建一个bridge时,它是一个独立的网络设备,只有一个端口连着协议栈,其它的端口啥都没连,这样的bridge没有任何实际功能。注意此时的Mac地址!
2.将bridge和veth设备相连
上篇网络虚拟化之虚拟网卡技术veth 中创建过一对veth设备,并配置上IP
sudo ip link add veth0 type veth peer name veth1
sudo ip addr add 10.1.1.100/24 dev veth0
sudo ip addr add 10.1.1.101/24 dev veth1
sudo ip link set veth0 up
sudo ip link set veth1 up
将veth0连上mbr0
sudo ip link set dev veth0 master mbr0
再次ifconfig看一下:
mbr0: flags=4163
inet6 fe80::2c0a:ceff:fe21:d304 prefixlen 64 scopeid 0x20
ether 92:53:19:cf:65:d4 txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 8 bytes 656 (656.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
mbr0的Mac地址变了,变成veth0的Mac地址。
通过bridge link命令可以看到mbr0上连接了哪些设备
sudo bridge link
网络连接如下:
5: veth5479fd5 state UP @(null):
mtu 1500 master docker0 state forwarding priority 32 cost 2
17: veth0 state UP @veth1:mtu 1500 master br0 state forwarding priority 32 cost 2
(本机还有另外一个veth,忽略。)
先来测试下通过veth0能否连接上veth1。
ping 10.1.1.101 -I veth0
PING 10.1.1.101 (10.1.1.101) from 10.1.1.100 veth0: 56(84) bytes of data.
^C
--- 10.1.1.101 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 1999ms
结果是没通!
veth0抓包如下:
sudo tcpdump -n -i veth0 -v
tcpdump: listening on veth0, link-type EN10MB (Ethernet), capture size 262144 bytes
17:35:10.736503 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 10.1.1.101 tell 10.1.1.100, length 28
17:35:10.736537 ARP, Ethernet (len 6), IPv4 (len 4), Reply 10.1.1.101 is-at 82:ed:5e:ed:4f:94, length 28
17:35:11.738057 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 10.1.1.101 tell 10.1.1.100, length 28
17:35:11.738103 ARP, Ethernet (len 6), IPv4 (len 4), Reply 10.1.1.101 is-at 82:ed:5e:ed:4f:94, length 28
17:35:12.740059 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 10.1.1.101 tell 10.1.1.100, length 28
17:35:12.740143 ARP, Ethernet (len 6), IPv4 (len 4), Reply 10.1.1.101 is-at 82:ed:5e:ed:4f:94, length 28
veth1抓包如下:
sudo ip netns exec test-yao 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
17:35:10.736516 ARP, Request who-has 10.1.1.101 tell 10.1.1.100, length 28
17:35:10.736536 ARP, Reply 10.1.1.101 is-at 82:ed:5e:ed:4f:94, length 28
17:35:11.738069 ARP, Request who-has 10.1.1.101 tell 10.1.1.100, length 28
17:35:11.738103 ARP, Reply 10.1.1.101 is-at 82:ed:5e:ed:4f:94, length 28
17:35:12.740122 ARP, Request who-has 10.1.1.101 tell 10.1.1.100, length 28
17:35:12.740142 ARP, Reply 10.1.1.101 is-at 82:ed:5e:ed:4f:94, length 28
都存在ARP包,并且回复了mac地址。
虚拟交互机mbr0的包数据:
sudo tcpdump -n -i mbr0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on mbr0, link-type EN10MB (Ethernet), capture size 262144 bytes
17:41:25.954578 ARP, Reply 10.1.1.101 is-at 82:ed:5e:ed:4f:94, length 28
17:41:26.956075 ARP, Reply 10.1.1.101 is-at 82:ed:5e:ed:4f:94, length 28
17:41:27.958091 ARP, Reply 10.1.1.101 is-at 82:ed:5e:ed:4f:94, length 28
mbr0收到了所有的ARP的Reply,但是并没有往协议栈发送,所以ping进程并读不到Mac就通信失败了。
结论:mbr0拦截在veth0和协议栈之间,将veth0本来要转发给协议栈的数据给拦截了,全部转发给bridge了,同时mbr0也可以向veth0发数据。
上面提到过如果mbr0不配置IP是不能转发数据包给协议栈了,在这种情况,通过veth0来ping veth1当然就不通了。
接下来给虚拟交换机mbr0配置上IP,可以配置成跟veth0一致试试。因为veth0已经不会从协议栈接收和发送数据,而是通过mbr0,veth0只负责连接mbr0和veth1,退化成一根网线。
sudo ip addr add 10.1.1.100/24 dev mbr0
看下路由表信息:
route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default gateway 0.0.0.0 UG 0 0 0 eth0
10.1.1.0 0.0.0.0 255.255.255.0 U 0 0 0 veth0
10.1.1.0 0.0.0.0 255.255.255.0 U 0 0 0 mbr0
link-local 0.0.0.0 255.255.0.0 U 1002 0 0 eth0
172.1.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
172.2.4.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
为避免veth0路由影响建议删除:sudo ip addr del 10.1.1.100/24 dev veth0
此时通过mbr0来访问veth1,试验一下:
ping 10.1.1.101 -I mbr0
PING 10.1.1.101 (10.1.1.101) from 10.1.1.100 mbr0: 56(84) bytes of data.
64 bytes from 10.1.1.101: icmp_seq=1 ttl=64 time=0.083 ms
64 bytes from 10.1.1.101: icmp_seq=2 ttl=64 time=0.107 ms
64 bytes from 10.1.1.101: icmp_seq=3 ttl=64 time=0.108 ms
成功啦!
PS: 此时直接ping 101地址,不指定mbr0也是可以通的;在未配置IP前也是不通的。
可以创建很多veth pair,一端都连在同一个bridge上,另一端连在容器里,这样就可以互相通讯,解决同一台主机上多个容器间的通讯问题。如果bridge指定IP后,主机可以访问容器内,容器内可以访问主机和外部。