當你想了解OpenStack的Neutron網絡,打開下面這張圖的時候,心里一定是崩潰的,看起來這些模塊連在一起很復雜,但其實和你家里的網絡很像,看不出來?看我來慢慢解析。
其實這個網絡的樣子更像是我上大學的時候的寢室里面的網絡。
作為一個已到中年的80后,在兩千年初上大學的時候,當時家用路由器的價格還很高,所以我們寢室買不起家用路由器,只好買一個hub,將整個寢室的四台電腦連接起來,整個寢室只有一個對外網口,於是寢室長的電腦需要買兩張網卡(當時買另外一張網卡是需要整個寢室分攤錢的),一張連接外網網口,一張連接Hub,其實是充當路由器的作用,其他的室友的網線都插到Hub上,任何一個人要上外網,必須把寢室長的電腦打開才可以。
整個寢室的網絡拓撲結構如下:
如果是現在家里有路由器的,拓撲架構如下:
家里的路由器一般都會有DHCP功能,家里的設備只要連接到路由器,就會自動被分配一個IP地址,家里的路由器會有一個內網IP地址192.168.1.1,
家里的電腦的網關一般就設置為這個地址,當家里的電腦上網的時候,也是通過路由器,從公網口出去到互聯網上訪問。
接下來,我們將整個寢室放在一台物理機里面,虛擬機是你的電腦,路由器和DHCP Server相當於家用路由器或者寢室長的電腦,外網網口訪問互聯網,所有的電腦都通過內網網口連接到一個Hub上,名為br-int,虛擬機要想訪問互聯網,需要通過Hub br-int連到路由器上,然后通過路由器將請求轉發到公網。
接下來的事情就慘了,你和你的寢室長鬧矛盾了,你們要分開宿舍住,分成兩個宿舍,對應上面的圖,路由器和VM分在兩台物理機上,這下把一個完整的br-int一刀兩斷,一半放在寢室長宿舍,一半放在你的宿舍。
可是只有你的寢室長有公網口可以上網,於是你偷偷的在兩個宿舍中間打了一個隧道,用網線通過隧道將兩個宿舍的兩個br-int連接起來,讓你的電腦和你寢室長的電腦感覺上,還是連到同一個br-int上,其實中間通過你的隧道中的網線做了轉發。
為什么要多一個br-tun這個虛擬交換機呢?主要通過br-int這一層將虛擬機之間的互聯和主機之間的互聯分成兩層來設計,tun的意思就是tunnel,就是隧道,隧道可以各種挖法,GRE,VXLAN都可以。
如果兩個寢室之間的互聯是通過VLAN,則結構如下:
這兩個加起來,是不是最上面的那張圖了。
接下來我們詳細解讀各個部分:
一、tap/tun設備
將guest system的網絡和host system的網絡連在一起
Tun/tap驅動程序中包含兩個部分,一部分是字符設備驅動,還有一部分是網卡驅動部分
二、Openvswitch的基本概念
br-int & br-tun由Openvswitch實現
Openvswitch是一個virutal switch, 支持Open Flow協議,當然也有一些硬件Switch也支持Open Flow協議,他們都可以被統一的Controller管理,從而實現物理機和虛擬機的網絡聯通。
Openvswitch創建出來的虛擬交換機會保存很多Flow Table包含許多entry,每個entry是對packet進行處理的規則
Match Field涵蓋TCP/IP協議各層:
-
Layer 1 – Tunnel ID, In Port, QoS priority, skb mark
-
Layer 2 – MAC address, VLAN ID, Ethernet type
-
Layer 3 – IPv4/IPv6 fields, ARP
-
Layer 4 – TCP/UDP, ICMP, ND
Action也主要包含下面的操作:
-
Output to port (port range, flood, mirror)
-
Discard, Resubmit to table x
-
Packet Mangling (Push/Pop VLAN header, TOS, ...)
-
Send to controller, Learn
這些Flow Table可以通過OpenFlow協議進行增刪查改。
這些FlowTable里面的規則執行順序安裝Table的優先級來,高優先級的先執行,低優先級的后執行,執行過程中可任意修改網絡包的內容,修改完畢后,可以扔給另一個Table,也可以直接output從一個虛擬口將包發出來。
三、解析br-int
br-int主要使用openvswitch中port的vlan功能
Port的一個重要的方面就是VLAN Configuration,有兩種模式:
模式一:trunk port
-
這個port不配置tag,配置trunks
-
如果trunks為空,則所有的VLAN都trunk,也就意味着對於所有的VLAN的包,本身帶什么VLAN ID,就是攜帶者什么VLAN ID,如果沒有設置VLAN,就屬於VLAN 0,全部允許通過。
-
如果trunks不為空,則僅僅帶着這些VLAN ID的包通過。
模式二:access port
-
這個port配置tag,從這個port進來的包會被打上這個tag
-
如果從其他的trunk port中進來的本身就帶有VLAN ID的包,如果VLAN ID等於tag,則會從這個port發出
-
從其他的access port上來的包,如果tag相同,也會被forward到這個port
-
從access port發出的包不帶VLAN ID
-
如果一個本身帶VLAN ID的包到達access port,即便VLAN ID等於tag,也會被拋棄。
例如要創建如下的虛擬網絡和虛擬交換機
執行以下的命令
ovs-vsctl add-br ubuntu_br
ip link add first_br type veth peer name first_if
ip link add second_br type veth peer name second_if
ip link add third_br type veth peer name third_if
ovs-vsctl add-port ubuntu_br first_br
ovs-vsctl add-port ubuntu_br second_br
ovs-vsctl add-port ubuntu_br third_br
ovs-vsctl set Port vnet0 tag=101
ovs-vsctl set Port vnet1 tag=102
ovs-vsctl set Port vnet2 tag=103
ovs-vsctl set Port first_br tag=103
ovs-vsctl clear Port second_br tag
ovs-vsctl set Port third_br trunks=101,102
需要監聽ARP,所以禁止MAC地址學習
ovs-vsctl set bridge ubuntu_br flood-vlans=101,102,103
實驗結果如下:
從192.168.100.102來ping 192.168.100.103,應該first_if和second_if能夠收到包
從192.168.100.100在ping 192.168.100.105, 則second_if和third_if可以收到包
從192.168.100.101來ping 192.168.100.104, 則second_if和third_if可以收到包
四、解析br-tun
br-tun主要使用openvswitch的tunnel功能和Flow功能。
Openvswitch支持三類Tunnel:gre,vxlan,ipsec_gre。
命令分別如下:
ovs-vsctl add-br testbr
ovs-vsctl add-port testbr gre0 -- set Interface gre0 type=gre options:local_ip=192.168.100.100 options:remote_ip=192.168.100.101
ovs-vsctl add-port testbr vxlan0 -- set Interface vxlan0 type=vxlan options:local_ip=192.168.100.100 options:remote_ip=192.168.100.102
ovs-vsctl add-port testbr ipsec0 -- set Interface ipsec0 type=ipsec_gre options:local_ip=192.168.100.101 options:remote_ip=192.168.100.102 options:psk=password
對於Flow Table的管理,由ovs-ofctl來控制
-
add−flow switch flow
-
mod−flows switch flow
-
del−flows switch [flow]
主要控制兩類
-
Match Field
-
Actions
對於Match Field,不同網絡層的表示方式不同,如下:
Actions有以下幾類:
-
output:port 和 output:NXM_NX_REG0[16..31]
-
enqueue:port:queue
-
mod_vlan_vid:vlan_vid
-
strip_vlan
-
mod_dl_src:mac 和 mod_dl_dst:mac
-
mod_nw_src:ip 和 mod_nw_dst:ip
-
mod_tp_src:port 和 mod_tp_dst:port
-
set_tunnel:id
-
resubmit([port],[table])
-
move:src[start..end]−>dst[start..end]
-
load:value−>dst[start..end]
-
learn(argument[,argument]...)
我們模擬創建一個如下的網絡拓撲結構,模擬OpenStack里面的行為
Flow Table的設計如下:
下面詳細描述FlowTable的添加過程,OpenStack也是這樣一個個規則添加進去的。
(1) 刪除所有的Flow
ovs-ofctl del-flows br-tun
(2) Table 0
從port 1進來的,由table 1處理
ovs-ofctl add-flow br-tun "hard_timeout=0 idle_timeout=0 priority=1 in_port=1 actions=resubmit(,1)"
從port 2/3進來的,由Table 3處理
ovs-ofctl add-flow br-tun "hard_timeout=0 idle_timeout=0 priority=1 in_port=2 actions=resubmit(,3)"
ovs-ofctl add-flow br-tun "hard_timeout=0 idle_timeout=0 priority=1 in_port=3 actions=resubmit(,3)"
默認丟棄
ovs-ofctl add-flow br-tun "hard_timeout=0 idle_timeout=0 priority=0 actions=drop"
(3) Table 1
對於單播,由table 20處理
ovs-ofctl add-flow br-tun "hard_timeout=0 idle_timeout=0 priority=1 table=1 dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,20)"
對於多播,由table 21處理
ovs-ofctl add-flow br-tun "hard_timeout=0 idle_timeout=0 priority=1 table=1 dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,21)"
(4) Table 2
默認丟棄
ovs-ofctl add-flow br-tun "hard_timeout=0 idle_timeout=0 priority=0 table=2 actions=drop"
(5) Table 3
默認丟棄
ovs-ofctl add-flow br-tun "hard_timeout=0 idle_timeout=0 priority=0 table=3 actions=drop"
Tunnel ID -> VLAN ID
ovs-ofctl add-flow br-tun "hard_timeout=0 idle_timeout=0 priority=1 table=3 tun_id=0x1 actions=mod_vlan_vid:1,resubmit(,10)"
ovs-ofctl add-flow br-tun "hard_timeout=0 idle_timeout=0 priority=1 table=3 tun_id=0x2 actions=mod_vlan_vid:2,resubmit(,10)"
(6) Table 10
MAC地址學習
ovs-ofctl add-flow br-tun "hard_timeout=0 idle_timeout=0 priority=1 table=10 actions=learn(table=20,priority=1,hard_timeout=300,NXM_OF_VLAN_TCI[0..11],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:0->NXM_OF_VLAN_TCI[],load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[],output:NXM_OF_IN_PORT[]),output:1"
-
Table 10是用來學習MAC地址的,學習的結果放在Table 20里面,Table20被稱為MAC learning table
-
NXM_OF_VLAN_TCI這個是VLAN Tag,在MAC Learning table中,每一個entry都是僅僅對某一個VLAN來說的,不同VLAN的learning table是分開的。在學習的結果的entry中,會標出這個entry是對於哪個VLAN的。
-
NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[]這個的意思是當前包里面的MAC Source Address會被放在學習結果的entry里面的dl_dst里面。這是因為每個switch都是通過Ingress包來學習,某個MAC從某個port進來,switch就應該記住以后發往這個MAC的包要從這個port出去,因而MAC source address就被放在了Mac destination address里面,因為這是為發送用的。
-
load:0->NXM_OF_VLAN_TCI[]意思是發送出去的時候,vlan tag設為0,所以結果中有actions=strip_vlan
-
load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[]意思是發出去的時候,設置tunnel id,進來的時候是多少,發送的時候就是多少,所以結果中有set_tunnel:0x3e9
-
output:NXM_OF_IN_PORT[]意思是發送給哪個port,由於是從port2進來的,因而結果中有output:2
(7) Table 20
這個是MAC Address Learning Table,如果不空就按照規則處理
如果為空,就使用默認規則,交給Table 21處理
ovs-ofctl add-flow br-tun "hard_timeout=0 idle_timeout=0 priority=0 table=20 actions=resubmit(,21)"
(8) Table 21
默認丟棄
ovs-ofctl add-flow br-tun "hard_timeout=0 idle_timeout=0 priority=0 table=21 actions=drop"
VLAN ID -> Tunnel ID
ovs-ofctl add-flow br-tun "hard_timeout=0 idle_timeout=0 priority=1table=21dl_vlan=1 actions=strip_vlan,set_tunnel:0x1,output:2,output:3"
ovs-ofctl add-flow br-tun "hard_timeout=0 idle_timeout=0 priority=1table=21dl_vlan=2 actions=strip_vlan,set_tunnel:0x2,output:2,output:3"
五、解析Router
使用namespace中的routing table
ip netns exec qrouter-5a74908c-712c-485c-aa9f-6c1e8b57e3e1 route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 16.158.164.1 0.0.0.0 UG 0 0 0 qg-52de6441-db
10.0.0.0 0.0.0.0 255.255.255.0 U 0 0 0 qr-e0967604-78
16.158.164.0 0.0.0.0 255.255.252.0 U 0 0 0 qg-52de6441-db
Floating IP使用namespace中的iptables的nat
ip netns exec qrouter-5a74908c-712c-485c-aa9f-6c1e8b57e3e1 iptables -t nat -nvL
六、解析br-ex
將namespace中的網絡和namespace外的網絡連接起來
歡迎關注微信公眾號