繼前兩篇介紹了tun/tap和veth以後,本篇將介紹Linux下經常使用的一種虛擬網絡設備,那就是bridge(橋)。php
本篇將經過實際的例子來一步一步解釋bridge是如何工做的。linux
首先,bridge是一個虛擬網絡設備,因此具備網絡設備的特徵,能夠配置IP、MAC地址等;其次,bridge是一個虛擬交換機,和物理交換機有相似的功能。docker
對於普通的網絡設備來講,只有兩端,從一端進來的數據會從另外一端出去,如物理網卡從外面網絡中收到的數據會轉發給內核協議棧,而從協議棧過來的數據會轉發到外面的物理網絡中。segmentfault
而bridge不一樣,bridge有多個端口,數據能夠從任何端口進來,進來以後從哪一個口出去和物理交換機的原理差很少,要看mac地址。緩存
咱們先用iproute2建立一個bridge:安全
dev@debian:~$ sudo ip link add name br0 type bridge dev@debian:~$ sudo ip link set br0 up
當剛建立一個bridge時,它是一個獨立的網絡設備,只有一個端口連着協議棧,其它的端口啥都沒連,這樣的bridge沒有任何實際功能,以下圖所示:bash
+----------------------------------------------------------------+ | | | +------------------------------------------------+ | | | Newwork Protocol Stack | | | +------------------------------------------------+ | | ↑ ↑ | |..............|................................|................| | ↓ ↓ | | +----------+ +------------+ | | | eth0 | | br0 | | | +----------+ +------------+ | | 192.168.3.21 ↑ | | | | | | | +--------------|-------------------------------------------------+ ↓ Physical Network
這裏假設eth0是咱們的物理網卡,IP地址是192.168.3.21,網關是192.168.3.1網絡
建立一對veth設備,並配置上IPless
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連上br0tcp
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
這裏爲了畫圖方便,省略了IP地址前面的192.168,好比.3.21就表示192.168.3.21
br0和veth0相連以後,發生了幾個變化:
br0和veth0之間鏈接起來了,而且是雙向的通道
協議棧和veth0之間變成了單通道,協議棧能發數據給veth0,但veth0從外面收到的數據不會轉發給協議棧
br0的mac地址變成了veth0的mac地址
至關於bridge在veth0和協議棧之間插了一腳,在veth0上面作了點小動做,將veth0原本要轉發給協議棧的數據給攔截了,所有轉發給bridge了,同時bridge也能夠向veth0發數據。
下面來檢驗一下是否是這樣的:
經過veth0 ping veth1失敗:
dev@debian:~$ ping -c 1 -I veth0 192.168.3.102 PING 192.168.2.1 (192.168.2.1) from 192.168.2.11 veth0: 56(84) bytes of data. From 192.168.2.11 icmp_seq=1 Destination Host Unreachable --- 192.168.2.1 ping statistics --- 1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms
爲何veth0加入了bridge以後,就ping不通veth2了呢? 先抓包看看:
#因爲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
從上面的抓包能夠看出,去和回來的流程都沒有問題,問題就出在veth0收到應答包後沒有給協議棧,而是給了br0,因而協議棧得不到veth1的mac地址,從而通訊失敗。
經過上面的分析能夠看出,給veth0配置IP沒有意義,由於就算協議棧傳數據包給veth0,應答包也回不來。這裏咱們就將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沒有配置IP,因此協議棧在路由的時候不會將數據包發給veth0,就算強制要求數據包經過veth0發送出去,但因爲veth0從另外一端收到的數據包只會給br0,因此協議棧仍是無法收到相應的arp應答包,致使通訊失敗。
這裏爲了表達更直觀,將協議棧和veth0之間的聯繫去掉了,veth0至關於一根網線。
再經過br0 ping一下veth1,結果成功
dev@debian:~$ ping -c 1 -I br0 192.168.3.102 PING 192.168.3.102 (192.168.3.102) from 192.168.3.101 br0: 56(84) bytes of data. 64 bytes from 192.168.3.102: icmp_seq=1 ttl=64 time=0.121 ms --- 192.168.3.102 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.121/0.121/0.121/0.000 ms
但ping網關仍是失敗,由於這個bridge上只有兩個網絡設備,分別是192.168.3.101和192.168.3.102,br0不知道192.168.3.1在哪。
dev@debian:~$ ping -c 1 -I br0 192.168.3.1 PING 192.168.3.1 (192.168.3.1) from 192.168.3.101 br0: 56(84) bytes of data. From 192.168.3.101 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添加到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
br0根本不區分接入進來的是物理設備仍是虛擬設備,對它來講都同樣的,都是網絡設備,因此當eth0加入br0以後,落得和上面veth0同樣的下場,從外面網絡收到的數據包將無條件的轉發給br0,本身變成了一根網線。
這時經過eth0來ping網關失敗,但因爲br0經過eth0這根網線連上了外面的物理交換機,因此連在br0上的設備都能ping通網關,這裏連上的設備就是veth1和br0本身,veth1是經過veth0這根網線連上去的,而br0能夠理解爲本身有一塊自帶的網卡。
#經過eth0來ping網關失敗 dev@debian:~$ ping -c 1 -I eth0 192.168.3.1 PING 192.168.3.1 (192.168.3.1) from 192.168.3.21 eth0: 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 #經過br0來ping網關成功 dev@debian:~$ ping -c 1 -I br0 192.168.3.1 PING 192.168.3.1 (192.168.3.1) from 192.168.3.101 br0: 56(84) bytes of data. 64 bytes from 192.168.3.1: icmp_seq=1 ttl=64 time=27.5 ms --- 192.168.3.1 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 27.518/27.518/27.518/0.000 ms #經過veth1來ping網關成功 dev@debian:~$ ping -c 1 -I veth1 192.168.3.1 PING 192.168.3.1 (192.168.3.1) from 192.168.3.102 veth1: 56(84) bytes of data. 64 bytes from 192.168.3.1: icmp_seq=1 ttl=64 time=68.8 ms --- 192.168.3.1 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 68.806/68.806/68.806/0.000 ms
因爲eth0已經變成了和網線差很少的功能,因此在eth0上配置IP已經沒有什麼意義了,而且還會影響協議棧的路由選擇,好比若是上面ping的時候不指定網卡的話,協議棧有可能優先選擇eth0,致使ping不通,因此這裏須要將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
上面的操做中有幾點須要注意:
若是是在虛擬機上作上述操做,記得打開網卡的混雜模式(不是在Linux裏面,而是在虛擬機的配置上面,如VirtualBox上相應虛擬機的網卡配置項裏面),否則veth1的網絡會不通,由於eth0不在混雜模式的話,會丟掉目的mac地址是veth1的數據包
上面雖然通了,但因爲Linux下arp的特性,當協議棧收到外面的arp請求時,不論是問101仍是102,都會回覆兩個arp應答,分別包含br0和veth1的mac地址,也即Linux以爲外面發給101和102的數據包從br0和veth1進協議棧都同樣,沒有區別。因爲回覆了兩個arp應答,而外面的設備只會用其中的一個,而且具體用哪一個會隨着時間發生變化,因而致使一個問題,就是外面回覆給102的數據包可能從101的br0上進來,即經過102 ping外面時,可能在veth1抓不到回覆包,而在br0上能抓到回覆包。說明數據流在交換機那層沒有徹底的隔離開,br0和veth1會收到對方的IP應答包。爲了解決上述問題,能夠配置rp_filter, arp_filter, arp_ignore, arp_announce等參數,但不建議這麼作,容易出錯,調試比較麻煩。
在無線網絡環境中,狀況會變得比較複雜,由於無線網絡須要登陸,登錄後無線路由器只認一個mac地址,全部從這臺機器出去的mac地址都必須是那一個,因而經過無線網卡上網的機器上的全部虛擬機想要上網的話,都必須依賴虛擬機管理軟件(如VirtualBox)將每一個虛擬機的網卡mac地址轉成出口的mac地址(即無線網卡的mac地址),數據包回來的時候還要轉回來,因此若是一個IP有兩個ARP應答包的話,有可能致使mac地址的轉換有問題,致使網絡不通,或者有時通有時不通。解決辦法就是將鏈接進br0的全部設備的mac地址都改爲和eth0同樣的mac地址,由於eth0的mac地址會被虛擬機正常的作轉換。在上面的例子中,執行下面的命令便可:
dev@debian:~$ sudo ip link set dev veth1 down #08:00:27:3b:0d:b9是eth0的mac地址 dev@debian:~$ sudo ip link set dev veth1 address 08:00:27:3b:0d:b9 dev@debian:~$ sudo ip link set dev veth1 up
在咱們常見的物理交換機中,有能夠配置IP和不能配置IP兩種,不能配置IP的交換機通常經過com口連上去作配置(更簡單的交換機連com口的沒有,不支持任何配置),而能配置IP的交換機能夠在配置好IP以後,經過該IP遠程鏈接上去作配置,從而更方便。
bridge就屬於後一種交換機,自帶虛擬網卡,能夠配置IP,該虛擬網卡一端連在bridge上,另外一端跟協議棧相連。和物理交換機同樣,bridge的工做不依賴於該虛擬網卡,但bridge工做不表明機器能連上網,要看組網方式。
刪除br0上的IP:
dev@debian:~$ sudo ip addr del 192.168.3.101/24 dev br0
因而網絡變成了這樣子,至關於br0的一個端口經過eth0連着交換機,另外一個端口經過veth0連着veth1:
+----------------------------------------------------------------+ | | | +------------------------------------------------+ | | | Newwork Protocol Stack | | | +------------------------------------------------+ | | ↑ | |.....................................................|..........| | ↓ | | +------+ +--------+ +-------+ +-------+ | | | | | | | | | .3.102| | | +------+ +--------+ +-------+ +-------+ | | | eth0 |<--->| br0 |<--->| veth0 | | veth1 | | | +------+ +--------+ +-------+ +-------+ | | ↑ ↑ ↑ | | | | | | | | +------------+ | | | | +------------|---------------------------------------------------+ ↓ Physical Network
ping網關成功,說明這種狀況下br0不配置IP對通訊沒有影響,數據包還能從veth1出去:
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=1.24 ms --- 192.168.3.1 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 1.242/1.242/1.242/0.000 ms
上面若是沒有veth0和veth1的話,刪除br0上的IP後,網絡將會不通,由於沒有設備和協議棧徹底相連
上面經過例子展現了bridge的功能,但例子中的那種部署方式沒有什麼實際用途,還不如在一個網卡上配置多個IP地址來的直接。這裏來介紹兩種常見的部署方式。
虛擬機經過tun/tap或者其它相似的虛擬網絡設備,將虛擬機內的網卡同br0鏈接起來,這樣就達到和真實交換機同樣的效果,虛擬機發出去的數據包先到達br0,而後由br0交給eth0發送出去,數據包都不須要通過host機器的協議棧,效率高。
+----------------------------------------------------------------+-----------------------------------------+-----------------------------------------+ | 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)
因爲容器運行在本身單獨的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,而後交給host機器的協議棧,因爲目的IP是外網IP,且host機器開啓了IP forward功能,因而數據包會經過eth0發送出去,因爲.9.1是內網IP,因此通常發出去以前會先作NAT轉換(NAT轉換和IP forward功能都須要本身配置)。因爲要通過host機器的協議棧,而且還要作NAT轉換,因此性能沒有上面虛擬機那種方案好,優勢是容器處於內網中,安全性相對要高點。(因爲數據包統一由IP層從eth0轉發出去,因此不存在mac地址的問題,在無線網絡環境下也工做良好)
上面兩種部署方案中,同一網段的每一個網卡都有本身單獨的協議棧,因此不存在上面說的多個ARP的問題