深入理解 Neutron -- OpenStack 網路實現(1):GRE 模式
概述
Neutron 的設計目標是實現“網路即服務”,為了達到這一目標,在設計上遵循了基於“軟體定義網路”實現網路虛擬化的原則,在實現上充分利用了 Linux 系統上的各種網路相關的技術。
理解了 Linux 系統上的這些概念將有利於快速理解 Neutron 的原理和實現。
涉及的 Linux 網路技術
bridge:網橋,Linux中用於表示一個能連線不同網路裝置的虛擬裝置,linux中傳統實現的網橋類似一個hub裝置,而ovs管理的網橋一般類似交換機。
br-int:bridge-integration,綜合網橋,常用於表示實現主要內部網路功能的網橋。
br-ex:bridge-external,外部網橋,通常表示負責跟外部網路通訊的網橋。
GRE:General Routing Encapsulation,一種通過封裝來實現隧道的方式。在openstack中一般是基於L3的gre,即original pkt/GRE/IP/Ethernet
VETH:虛擬ethernet介面,通常以pair的方式出現,一端發出的網包,會被另一端接收,可以形成兩個網橋之間的通道。
qvb:neutron veth, Linux Bridge-side
qvo:neutron veth, OVS-side
TAP裝置:模擬一個二層的網路裝置,可以接受和傳送二層網包。
TUN裝置:模擬一個三層的網路裝置,可以接受和傳送三層網包。
iptables:Linux 上常見的實現安全策略的防火牆軟體。
Vlan:虛擬 Lan,同一個物理 Lan 下用標籤實現隔離,可用標號為1-4094。
VXLAN:一套利用 UDP 協議作為底層傳輸協議的 Overlay 實現。一般認為作為 VLan 技術的延伸或替代者。
namespace:用來實現隔離的一套機制,不同 namespace 中的資源之間彼此不可見。
基本概念
Neutron管理下面的實體:
網路:隔離的 L2 域,可以是虛擬、邏輯或交換,同一個網路中的主機彼此 L2 可見。
子網:隔離的 L3 域,IP 地址塊。其中每個機器有一個 IP,同一個子網的主機彼此 L3 可見。
埠:網路上虛擬、邏輯或交換埠。 所有這些實體都是虛擬的,擁有自動生成的唯一標示id,支援CRUD功能,並在資料庫中跟蹤記錄狀態。
網路
隔離的 L2 廣播域,一般是建立它的使用者所有。使用者可以擁有多個網路。網路是最基礎的,子網和埠都需要關聯到網路上。
網路上可以有多個子網。同一個網路上的主機一般可以通過交換機或路由器連通起來。
子網
隔離的 L3 域,子網代表了一組分配了 IP 的虛擬機器。每個子網必須有一個 CIDR 和關聯到一個網路。IP 可以從 CIDR 或者使用者指定池中選取。
子網可能會有一個閘道器、一組 DNS 和主機路由。不同子網之間 L2 是互相不可見的,必須通過一個三層閘道器(即路由器)經過 L3 上進行通訊。
埠
可以進出流量的介面,往往繫結上若干 MAC 地址和 IP 地址,以進行定址。一般為虛擬交換機上的虛擬介面。
虛擬機器掛載網路卡到埠上,通過埠訪問網路。當埠有 IP 的時候,意味著它屬於某個子網。
抽象系統架構
無論哪種具體的網路虛擬化實現,在啟用 DVR 特性(J 版本以後支援)之前,所有流量(東西向、南北向)都需要經過網路節點的轉發;DVR 特性則允許東西向流量和帶有 Floating IP 的南北向流量不經過網路節點的轉發,直接從計算節點的外部網路出去。
GRE 模式
下圖給出了在OpenStack中網路實現的一個簡化的架構示意。
一般的,OpenStack中網路實現包括vlan、gre、vxlan 等模式,此處以gre模式為例。
在OpenStack中,所有網路有關的邏輯管理均在Network節點中實現,例如DNS、DHCP以及路由等。Compute節點上只需要對所部屬的虛擬機器提供基本的網路功能支援,包括隔離不同租戶的虛擬機器和進行一些基本的安全策略管理(即security group)。
計算節點
Compute節點上包括兩臺虛擬機器VM1和VM2,分別經過一個網橋(如qbr-XXX)連線到 br-int 網橋上。br-int 網橋再經過 br-tun 網橋(物理網路是 GRE 實現)連線到物理主機外部網路。
對於物理網路通過vlan來隔離的情況,則一般會存在一個br-eth網橋,替代 br-tun 網橋。
qbr
在VM1中,虛擬機器的網路卡實際上連線到了物理機的一個TAP裝置(即A,常見名稱如tap-XXX)上,A則進一步通過VETH pair(A-B)連線到網橋qbr-XXX的埠vnet0(埠B)上,之後再通過VETH pair(C-D)連到br-int網橋上。一般C的名字格式為qvb-XXX,而D的名字格式為qvo-XXX。注意它們的名稱除了字首外,後面的id都是一樣的,表示位於同一個虛擬機器網路到物理機網路的連線上。
之所以TAP裝置A沒有直接連線到網橋br-int上,是因為OpenStack需要通過iptables實現security group的安全策略功能。目前openvswitch並不支援應用iptables規則的Tap裝置。
因為qbr的存在主要是為了輔助iptables來實現security group功能,有時候也被稱為firewall bridge。詳見security group部分的分析【後面篇章會給出】。
br-int
一個典型的br-int的埠如下所示:
Bridge br-int
Port "qvo-XXX"
tag: 1
Interface "qvo-XXX"
Port patch-tun
Interface patch-tun
type: patch
options: {peer=patch-int}
Port br-int
Interface br-int
type: internal
|
其中br-int為內部埠。
埠patch-tun(即埠E,埠號為1)連線到br-tun上,實現到外部網路的隧道。 埠qvo-XXX(即埠D,埠號為2)帶有tag1,說明這個口是一個1號vlan的access埠。虛擬機器發出的從該埠到達br-int的網包將被自動帶上vlan tag 1,而其他帶有vlan tag 1的網包則可以在去掉vlan tag後從該埠發出(具體請查詢vlan access埠)。這個vlan
tag是用來實現不同網路相互隔離的,比如租戶建立一個網路(neutron net-create),則會被分配一個唯一的vlan tag。
br-int在GRE模式中作為一個NORMAL交換機使用,因此有效規則只有一條正常轉發。如果兩個在同一主機上的vm屬於同一個tenant的(同一個vlan tag),則它們之間的通訊只需要經過br-int即可。
# ovs-ofctl dump-flows br-int
NXST_FLOW reply (xid=0x4):
cookie=0x0, duration=10727.864s, table=0, n_packets=198, n_bytes=17288, idle_age=13, priority=1 actions=NORMAL
|
br-tun
一個典型的br-tun上的埠類似:
Bridge br-tun
Port patch-int
Interface patch-int
type: patch
options: {peer=patch-tun}
Port "gre-1"
Interface "gre-1"
type: gre
options: {in_key=flow, local_ip="10.0.0.101", out_key=flow, remote_ip="10.0.0.100"}
Port br-tun
Interface br-tun
type: internal
|
其中patch-int(即埠F,埠號為1)是連線到br-int上的veth pair的埠,gre-1口(即埠G,埠號為2)對應vm到外面的隧道。
gre-1埠是虛擬gre埠,當網包傳送到這個埠的時候,會經過核心封包,然後從10.0.0.101傳送到10.0.0.100,即從本地的物理網路卡(10.0.0.101)發出。
br-tun將帶有vlan tag的vm跟外部通訊的流量轉換到對應的gre隧道,這上面要實現主要的轉換邏輯,規則要複雜,一般通過多張表來實現。
典型的轉發規則為:
# ovs-ofctl dump-flows br-tun
NXST_FLOW reply (xid=0x4):
cookie=0x0, duration=10970.064s, table=0, n_packets=189,
n_bytes=16232, idle_age=16, priority=1,in_port=1 actions=resubmit(,1)
cookie=0x0, duration=10906.954s, table=0, n_packets=29, n_bytes=5736, idle_age=16,
priority=1,in_port=2 actions=resubmit(,2)
cookie=0x0, duration=10969.922s, table=0, n_packets=3, n_bytes=230, idle_age=10962,
priority=0 actions=drop
cookie=0x0, duration=10969.777s, table=1, n_packets=26, n_bytes=5266, idle_age=16,
priority=0,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,20)
cookie=0x0, duration=10969.631s, table=1, n_packets=163, n_bytes=10966, idle_age=21,
priority=0,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,21)
cookie=0x0, duration=688.456s, table=2, n_packets=29, n_bytes=5736,
idle_age=16, priority=1,tun_id=0x1 actions=mod_vlan_vid:1,resubmit(,10)
cookie=0x0, duration=10969.488s, table=2, n_packets=0, n_bytes=0, idle_age=10969, priority=0 actions=drop
cookie=0x0, duration=10969.343s, table=3, n_packets=0, n_bytes=0, idle_age=10969, priority=0 actions=drop
cookie=0x0, duration=10969.2s, table=10, n_packets=29, n_bytes=5736, idle_age=16,
priority=1 actions=learn(table=20,hard_timeout=300,priority=1,
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
cookie=0x0, duration=682.603s, table=20, n_packets=26, n_bytes=5266,
hard_timeout=300, idle_age=16, hard_age=16, priority=1,vlan_tci=0x0001/0x0fff,
dl_dst=fa:16:3e:32:0d:db actions=load:0->NXM_OF_VLAN_TCI[],load:0x1->NXM_NX_TUN_ID[],output:2
cookie=0x0, duration=10969.057s, table=20, n_packets=0, n_bytes=0,
idle_age=10969, priority=0 actions=resubmit(,21)
cookie=0x0, duration=688.6s, table=21, n_packets=161, n_bytes=10818,
idle_age=21, priority=1,dl_vlan=1 actions=strip_vlan,set_tunnel:0x1,output:2
cookie=0x0, duration=10968.912s, table=21, n_packets=2, n_bytes=148,
idle_age=689, priority=0 actions=drop
|
其中,表0中有3條規則:從埠1(即patch-int)來的,扔到表1,從埠2(即gre-1)來的,扔到表2。
cookie=0x0, duration=10970.064s, table=0, n_packets=189, n_bytes=16232,
idle_age=16, priority=1,in_port=1 actions=resubmit(,1)
cookie=0x0, duration=10906.954s, table=0, n_packets=29,
n_bytes=5736, idle_age=16, priority=1,in_port=2 actions=resubmit(,2)
cookie=0x0, duration=10969.922s, table=0, n_packets=3,
n_bytes=230, idle_age=10962, priority=0 actions=drop
|
表1有2條規則:如果是單播(00:00:00:00:00:00/01:00:00:00:00:00),則扔到表20;如果是多播等(01:00:00:00:00:00/01:00:00:00:00:00),則扔到表21。
cookie=0x0, duration=10969.777s, table=1, n_packets=26, n_bytes=5266,
idle_age=16, priority=0,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,20)
cookie=0x0, duration=10969.631s, table=1, n_packets=163, n_bytes=10966,
idle_age=21, priority=0,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,21)
|
表2有2條規則:如果是tunnel 1的網包,則修改其vlan id為1,並扔到表10;非tunnel 1的網包,則丟棄。
cookie=0x0, duration=688.456s, table=2, n_packets=29, n_bytes=5736,
idle_age=16, priority=1,tun_id=0x1 actions=mod_vlan_vid:1,resubmit(,10)
cookie=0x0, duration=10969.488s, table=2, n_packets=0,
n_bytes=0, idle_age=10969, priority=0 actions=drop
|
表3只有1條規則:丟棄。
表10有一條規則,基於learn行動來建立反向(從gre埠抵達,且目標是到vm的網包)的規則。learn行動並非標準的openflow行動,是openvswitch自身的擴充套件行動,這個行動可以根據流內容動態來修改流表內容。這條規則首先建立了一條新的流(該流對應vm從br-tun的gre埠發出的規則):其中table=20表示規則新增在表20;NXM_OF_VLAN_TCI[0..11]表示匹配包自帶的vlan
id;NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[]表示L2目標地址需要匹配包的L2源地址;load:0->NXM_OF_VLAN_TCI[],去掉vlan,load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[],新增tunnel號為原始tunnel號;output:NXM_OF_IN_PORT[],發出埠為原始包抵達的埠。最後規則將匹配的網包從埠1(即patch-int)發出。
cookie=0x0, duration=10969.2s, table=10, n_packets=29, n_bytes=5736, idle_age=16,
priority=1 actions=learn(table=20,hard_timeout=300,priority=1,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
|
表20中有兩條規則,其中第一條即表10中規則利用learn行動建立的流表項,第2條提交其他流到表21。
cookie=0x0, duration=682.603s, table=20, n_packets=26, n_bytes=5266, hard_timeout=300,
idle_age=16, hard_age=16, priority=1,vlan_tci=0x0001/0x0fff,
dl_dst=fa:16:3e:32:0d:db actions=load:0->NXM_OF_VLAN_TCI[],load:0x1->NXM_NX_TUN_ID[],output:2
cookie=0x0, duration=10969.057s, table=20, n_packets=0, n_bytes=0,
idle_age=10969, priority=0 actions=resubmit(,21)
|
表21有2條規則,第一條是匹配所有目標vlan為1的網包,去掉vlan,然後從埠2(gre埠)發出。第二條是丟棄。
cookie=0x0, duration=688.6s, table=21, n_packets=161, n_bytes=10818,
idle_age=21, priority=1,dl_vlan=1 actions=strip_vlan,set_tunnel:0x1,output:2
cookie=0x0, duration=10968.912s, table=21, n_packets=2, n_bytes=148,
idle_age=689, priority=0 actions=drop
|
這些規則所組成的整體轉發邏輯如下圖所示。
網路節點
br-tun
Bridge br-tun
Port br-tun
Interface br-tun
type: internal
Port patch-int
Interface patch-int
type: patch
options: {peer=patch-tun}
Port "gre-2"
Interface "gre-2"
type: gre
options: {in_key=flow, local_ip="10.0.0.100", out_key=flow, remote_ip="10.0.0.101"}
|
Compute節點上發往GRE隧道的網包最終抵達Network節點上的br-tun,該網橋的規則包括:
# ovs-ofctl dump-flows br-tun
NXST_FLOW reply (xid=0x4):
cookie=0x0, duration=19596.862s, table=0, n_packets=344, n_bytes=66762,
idle_age=4, priority=1,in_port=1 actions=resubmit(,1)
cookie=0x0, duration=19537.588s, table=0, n_packets=625, n_bytes=125972,
idle_age=4, priority=1,in_port=2 actions=resubmit(,2)
cookie=0x0, duration=19596.602s, table=0, n_packets=2, n_bytes=140,
idle_age=19590, priority=0 actions=drop
cookie=0x0, duration=19596.343s, table=1, n_packets=323, n_bytes=65252,
idle_age=4, priority=0,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,20)
cookie=0x0, duration=19596.082s, table=1, n_packets=21, n_bytes=1510,
idle_age=5027, priority=0,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,21)
cookie=0x0, duration=9356.289s, table=2, n_packets=625, n_bytes=125972,
idle_age=4, priority=1,tun_id=0x1 actions=mod_vlan_vid:1,resubmit(,10)
cookie=0x0, duration=19595.821s, table=2, n_packets=0, n_bytes=0,
idle_age=19595, priority=0 actions=drop
cookie=0x0, duration=19595.554s, table=3, n_packets=0, n_bytes=0, idle_age=19595, priority=0 actions=drop
cookie=0x0, duration=19595.292s, table=10, n_packets=625, n_bytes=125972, idle_age=4,
priority=1 actions=learn(table=20,hard_timeout=300,priority=1,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
cookie=0x0, duration=9314.338s, table=20, n_packets=323, n_bytes=65252,
hard_timeout=300, idle_age=4, hard_age=3, priority=1,vlan_tci=0x0001/0x0fff,
dl_dst=fa:16:3e:cb:11:f6 actions=load:0->NXM_OF_VLAN_TCI[],load:0x1->NXM_NX_TUN_ID[],output:2
cookie=0x0, duration=19595.026s, table=20, n_packets=0, n_bytes=0,
idle_age=19595, priority=0 actions=resubmit(,21)
cookie=0x0, duration=9356.592s, table=21, n_packets=9, n_bytes=586,
idle_age=5027, priority=1,dl_vlan=1 actions=strip_vlan,set_tunnel:0x1,output:2
cookie=0x0, duration=19594.759s, table=21, n_packets=12, n_bytes=924,
idle_age=5057, priority=0 actions=drop
|
這些規則跟Compute節點上br-tun的規則相似,完成tunnel跟vlan之間的轉換。
br-int
Bridge br-int
Port "qr-ff19a58b-3d"
tag: 1
Interface "qr-ff19a58b-3d"
type: internal
Port br-int
Interface br-int
type: internal
Port patch-tun
Interface patch-tun
type: patch
options: {peer=patch-int}
Port "tap4385f950-8b"
tag: 1
Interface "tap4385f950-8b"
type: internal
|
該整合網橋上掛載了很多程式來提供網路服務,包括路由器、DHCP伺服器等。這些程式不同的租戶可能都需要,彼此的地址空間可能衝突,也可能跟物理網路的地址空間衝突,因此都執行在獨立的網路名字空間中。 規則跟computer節點的br-int規則一致,表現為一個正常交換機。
# ovs-ofctl dump-flows br-int
NXST_FLOW reply (xid=0x4):
cookie=0x0, duration=18198.244s, table=0, n_packets=849, n_bytes=164654, idle_age=43, priority=1 actions=NORMAL
|
網路名字空間
在linux中,網路名字空間可以被認為是隔離的擁有單獨網路棧(網路卡、路由轉發表、iptables)的環境。網路名字空間經常用來隔離網路裝置和服務,只有擁有同樣網路名字空間的裝置,才能看到彼此。 可以用ip netns list命令來檢視已經存在的名字空間。
# ip netns
qdhcp-88b1609c-68e0-49ca-a658-f1edff54a264
qrouter-2d214fde-293c-4d64-8062-797f80ae2d8f
|
qdhcp開頭的名字空間是dhcp伺服器使用的,qrouter開頭的則是router服務使用的。 可以通過 ip netns exec namespaceid command 來在指定的網路名字空間中執行網路命令,例如
# ip netns exec qdhcp-88b1609c-68e0-49ca-a658-f1edff54a264 ip addr
71: ns-f14c598d-98: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether fa:16:3e:10:2f:03 brd ff:ff:ff:ff:ff:ff
inet 10.1.0.3/24 brd 10.1.0.255 scope global ns-f14c598d-98
inet6 fe80::f816:3eff:fe10:2f03/64 scope link
valid_lft forever preferred_lft forever
|
可以看到,dhcp服務的網路名字空間中只有一個網路介面“ns-f14c598d-98”,它連線到br-int的tapf14c598d-98介面上。
dhcp 服務
dhcp服務是通過dnsmasq程式(輕量級伺服器,可以提供dns、dhcp、tftp等服務)來實現的,該程式繫結到dhcp名字空間中的br-int的介面上。可以檢視相關的程式。
# ps -fe | grep 88b1609c-68e0-49ca-a658-f1edff54a264
nobody 23195 1 0 Oct26 ? 00:00:00 dnsmasq --no-hosts --no-resolv --strict-order --bind-interfaces
--interface=ns-f14c598d-98 --except-interface=lo
--pid-file=/var/lib/neutron/dhcp/88b1609c-68e0-49ca-a658-f1edff54a264/pid
--dhcp-hostsfile=/var/lib/neutron/dhcp/88b1609c-68e0-49ca-a658-f1edff54a264/host
--dhcp-optsfile=/var/lib/neutron/dhcp/88b1609c-68e0-49ca-a658-f1edff54a264/opts
--dhcp-script=/usr/bin/neutron-dhcp-agent-dnsmasq-lease-update --leasefile-ro
--dhcp-range=tag0,10.1.0.0,static,120s --conf-file= --domain=openstacklocal
root 23196 23195 0 Oct26 ? 00:00:00 dnsmasq --no-hosts --no-resolv
--strict-order --bind-interfaces
--interface=ns-f14c598d-98 --except-interface=lo
--pid-file=/var/lib/neutron/dhcp/88b1609c-68e0-49ca-a658-f1edff54a264/pid
--dhcp-hostsfile=/var/lib/neutron/dhcp/88b1609c-68e0-49ca-a658-f1edff54a264/host
--dhcp-optsfile=/var/lib/neutron/dhcp/88b1609c-68e0-49ca-a658-f1edff54a264/opts
--dhcp-script=/usr/bin/neutron-dhcp-agent-dnsmasq-lease-update --leasefile-ro
--dhcp-range=tag0,10.1.0.0,static,120s --conf-file= --domain=openstacklocal
|
router服務
首先,要理解什麼是router,router是提供跨subnet的互聯功能的。比如使用者的內部網路中主機想要訪問外部網際網路的地址,就需要router來轉發(因此,所有跟外部網路的流量都必須經過router)。目前router的實現是通過iptables進行的。 同樣的,router服務也執行在自己的名字空間中,可以通過如下命令檢視:
# ip netns exec qrouter-2d214fde-293c-4d64-8062-797f80ae2d8f ip addr
66: qg-d48b49e0-aa: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether fa:16:3e:5c:a2:ac brd ff:ff:ff:ff:ff:ff
inet 172.24.4.227/28 brd 172.24.4.239 scope global qg-d48b49e0-aa
inet 172.24.4.228/32 brd 172.24.4.228 scope global qg-d48b49e0-aa
inet6 fe80::f816:3eff:fe5c:a2ac/64 scope link
valid_lft forever preferred_lft forever
68: qr-c2d7dd02-56: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether fa:16:3e:ea:64:6e brd ff:ff:ff:ff:ff:ff
inet 10.1.0.1/24 brd 10.1.0.255 scope global qr-c2d7dd02-56
inet6 fe80::f816:3eff:feea:646e/64 scope link
valid_lft forever preferred_lft forever
|
可以看出,該名字空間中包括兩個網路介面。
第一個介面qg-d48b49e0-aa(即K)是外部介面(qg=q gateway),將路由器的閘道器指向預設閘道器(通過router-gateway-set命令指定),這個介面連線到br-ex上的tapd48b49e0-aa(即L)。
第二個介面qr-c2d7dd02-56(即N,qr=q bridge)跟br-int上的tapc2d7dd02-56口(即M)相連,將router程式連線到整合網橋上。
檢視該名字空間中的路由表:
# ip netns exec qrouter-2d214fde-293c-4d64-8062-797f80ae2d8f ip route
172.24.4.224/28 dev qg-d48b49e0-aa proto kernel scope link src 172.24.4.227
10.1.0.0/24 dev qr-c2d7dd02-56 proto kernel scope link src 10.1.0.1
default via 172.24.4.225 dev qg-d48b49e0-aa
|
其中,第一條規則是將到172.24.4.224/28段的訪問都從網路卡qg-d48b49e0-aa(即K)發出。
第二條規則是將到10.1.0.0/24段的訪問都從網路卡qr-c2d7dd02-56(即N)發出。 最後一條是預設路由,所有的通過qg-d48b49e0-aa網路卡(即K)發出。 floating ip服務同樣在路由器名字空間中實現,例如如果繫結了外部的floating ip 172.24.4.228到某個虛擬機器10.1.0.2,則nat表中規則為:
# ip netns exec qrouter-2d214fde-293c-4d64-8062-797f80ae2d8f iptables -t nat -S
-P PREROUTING ACCEPT
-P POSTROUTING ACCEPT
-P OUTPUT ACCEPT
-N neutron-l3-agent-OUTPUT
-N neutron-l3-agent-POSTROUTING
-N neutron-l3-agent-PREROUTING
-N neutron-l3-agent-float-snat
-N neutron-l3-agent-snat
-N neutron-postrouting-bottom
-A PREROUTING -j neutron-l3-agent-PREROUTING
-A POSTROUTING -j neutron-l3-agent-POSTROUTING
-A POSTROUTING -j neutron-postrouting-bottom
-A OUTPUT -j neutron-l3-agent-OUTPUT
-A neutron-l3-agent-OUTPUT -d 172.24.4.228/32 -j DNAT --to-destination 10.1.0.2
-A neutron-l3-agent-POSTROUTING ! -i qg-d48b49e0-aa !
-o qg-d48b49e0-aa -m conntrack ! --ctstate DNAT -j ACCEPT
-A neutron-l3-agent-PREROUTING -d 169.254.169.254/32 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 9697
-A neutron-l3-agent-PREROUTING -d 172.24.4.228/32 -j DNAT --to-destination 10.1.0.2
-A neutron-l3-agent-float-snat -s 10.1.0.2/32 -j SNAT --to-source 172.24.4.228
-A neutron-l3-agent-snat -j neutron-l3-agent-float-snat
-A neutron-l3-agent-snat -s 10.1.0.0/24 -j SNAT --to-source 172.24.4.227
-A neutron-postrouting-bottom -j neutron-l3-agent-snat
|
其中SNAT和DNAT規則完成外部floating ip到內部ip的對映:
-A neutron-l3-agent-OUTPUT -d 172.24.4.228/32 -j DNAT --to-destination 10.1.0.2
-A neutron-l3-agent-PREROUTING -d 172.24.4.228/32 -j DNAT --to-destination 10.1.0.2
-A neutron-l3-agent-float-snat -s 10.1.0.2/32 -j SNAT --to-source 172.24.4.228
|
另外有一條SNAT規則把所有其他的內部IP出來的流量都對映到外部IP 172.24.4.227。這樣即使在內部虛擬機器沒有外部IP的情況下,也可以發起對外網的訪問。
-A neutron-l3-agent-snat -s 10.1.0.0/24 -j SNAT --to-source 172.24.4.227
|
br-ex
Bridge br-ex
Port "eth1"
Interface "eth1"
Port br-ex
Interface br-ex
type: internal
Port "qg-1c3627de-1b"
Interface "qg-1c3627de-1b"
type: internal
|
br-ex上直接連線到外部物理網路,一般情況下閘道器在物理網路中已經存在,則直接轉發即可。
# ovs-ofctl dump-flows br-exNXST_FLOW reply (xid=0x4):
cookie=0x0, duration=23431.091s, table=0, n_packets=893539,
n_bytes=504805376, idle_age=0, priority=0 actions=NORMAL
|
如果對外部網路的閘道器地址配置到了br-ex(即br-ex作為一個閘道器):
# ip addr add 172.24.4.225/28 dev br-ex
|
需要將內部虛擬機器發出的流量進行SNAT,之後發出。
# iptables -A FORWARD -d 172.24.4.224/28 -j ACCEPT
# iptables -A FORWARD -s 172.24.4.224/28 -j ACCEPT
# iptables -t nat -I POSTROUTING 1 -s 172.24.4.224/28 -j MASQUERADE
|
深入理解 Neutron -- OpenStack 網路實現(2):VLAN 模式
Vlan模式下的系統架構跟GRE模式下類似,如下圖所示。
需要注意的是,在vlan模式下,vlan tag的轉換需要在br-int和br-ethx兩個網橋上進行相互配合。即br-int負責從int-br-ethX過來的包(帶外部vlan)轉換為內部vlan,而br-ethx負責從phy-br-ethx過來的包(帶內部vlan)轉化為外部的vlan。
(個人對vlan tag的理解,應該是對vlan的一個人為標記,起到識別的作用)
下面進行一些細節的補充討論,以Vlan作為物理網路隔離的實現。假如要實現同一個租戶下兩個子網,如下圖所示:
計算節點
檢視網橋資訊,主要包括兩個網橋:br-int和br-eth1:
[root@Compute ~]# ovs-vsctl show
f758a8b8-2fd0-4a47-ab2d-c49d48304f82
Bridge "br-eth1"
Port "phy-br-eth1"
Interface "phy-br-eth1"
Port "br-eth1"
Interface "br-eth1"
type: internal
Port "eth1"
Interface "eth1"
Bridge br-int
Port "qvoXXX"
tag: 1
Interface "qvoXXX"
Port "qvoYYY"
tag: 1
Interface "qvoYYY"
Port "qvoZZZ"
tag: 2
Interface "qvoZZZ"
Port "qvoWWW"
tag: 2
Interface "qvoWWW"
Port "int-br-eth1"
Interface "int-br-eth1"
Port br-int
Interface br-int
type: internal
|
類似GRE模式下,br-int負責租戶隔離,br-eth1負責跟計算節點外的網路通訊。 在Vlan模式下,租戶的流量隔離是通過vlan來進行的,因此此時包括兩種vlan,虛擬機器在Compute Node內流量帶有的local vlan和在Compute Node之外物理網路上隔離不同租戶的vlan。
br-int和br-eth1分別對從埠int-br-eth1和phy-br-eth1上到達的網包進行vlan tag的處理。此處有兩個網,分別帶有兩個vlan tag(內部tag1對應外部tag101,內部tag2對應外部tag102)。 其中,安全組策略仍然在qbr相關的iptables上實現。
br-int
與GRE模式不同的是,br-int完成從br-eth1上過來流量(從口int-br-eth1到達)的vlan tag轉換,可能的規則為
#ovs-ofctl dump-flows br-int
cookie=0x0, duration=100.795s, table=0, n_packets=6,
n_bytes=468, idle_age=90, priority=2,in_port=3 actions=drop
cookie=0x0, duration=97.069s, table=0, n_packets=22, n_bytes=6622, idle_age=31,
priority=3,in_port=3,dl_vlan=101 actions=mod_vlan_vid:1,NORMAL
cookie=0x0, duration=95.781s, table=0, n_packets=8, n_bytes=1165, idle_age=11,
priority=3,in_port=3,dl_vlan=102 actions=mod_vlan_vid:2,NORMAL
cookie=0x0, duration=103.626s, table=0, n_packets=47,
n_bytes=13400, idle_age=11, priority=1 actions=NORMAL
|
br-eth1
br-eth1上負責從br-int上過來的流量(從口phy-br-eth1到達),實現local vlan到外部vlan的轉換。
#ovs-ofctl dump-flows br-eth0
NXST_FLOW reply (xid=0x4):
cookie=0x0, duration=73.461s, table=0, n_packets=51, n_bytes=32403,
idle_age=2, hard_age=65534, priority=4,in_port=4,dl_vlan=1 actions=mod_vlan_vid:101,NORMAL
cookie=0x0, duration=83.461s, table=0, n_packets=51, n_bytes=32403,
idle_age=2, hard_age=65534, priority=4,in_port=4,dl_vlan=2 actions=mod_vlan_vid:102,NORMAL
cookie=0x0, duration=651.538s, table=0, n_packets=72, n_bytes=3908,
idle_age=2574, hard_age=65534, priority=2,in_port=4 actions=drop
cookie=0x0, duration=654.002s, table=0, n_packets=31733, n_bytes=6505880,
idle_age=2, hard_age=65534, priority=1 actions=NORMAL
|
網路節點
類似GRE模式下,br-eth1收到到達的網包,int-br-eth1和phy-br-eth1上分別進行vlan轉換,保證到達br-int上的網包都是帶有內部vlan tag,到達br-eth1上的都是帶有外部vlan tag。br-ex則完成到OpenStack以外網路的連線。 檢視網橋資訊,包括三個網橋,br-eth1、br-int和br-ex。
#ovs
3bd78da8-d3b5-4112-a766-79506a7e2801
Bridge br-ex
Port "qg-VVV"
Interface "qg-VVV"
type: internal
Port br-ex
Interface br-ex
type: internal
Port "eth0"
Interface "eth0"
Bridge br-int
Port br-int
Interface br-int
type: internal
Port "int-br-eth1"
Interface "int-br-eth0"
Port "tapXXX"
tag: 1
Interface "tapXXX"
type: internal
Port "tapWWW"
tag: 2
Interface "tapWWW"
type: internal
Port "qr-YYY"
tag: 1
Interface "qr-YYY"
type: internal
Port "qr-ZZZ"
tag: 2
Interface "qr-ZZZ"
type: internal
Bridge "br-eth1"
Port "phy-br-eth1"
Interface "phy-br-eth1"
Port "br-eth1"
Interface "br-eth1"
type: internal
Port "eth1"
Interface "eth1"
|
br-eth1
br-eth1主要負責把物理網路上外部vlan轉化為local vlan。
#ovs-ofctl dump-flows br-eth1
NXST_FLOW reply (xid=0x4):
cookie=0x0, duration=144.33s, table=0, n_packets=13, n_bytes=28404, idle_age=24,
hard_age=65534, priority=4,in_port=5,dl_vlan=101 actions=mod_vlan_vid:1,NORMAL
cookie=0x0, duration=144.33s, table=0, n_packets=13, n_bytes=28404, idle_age=24,
hard_age=65534, priority=4,in_port=5,dl_vlan=102 actions=mod_vlan_vid:2,NORMAL
cookie=0x0, duration=608.373s, table=0, n_packets=23, n_bytes=1706,
idle_age=65534, hard_age=65534, priority=2,in_port=5 actions=drop
cookie=0x0, duration=675.373s, table=0, n_packets=58,
n_bytes=10625, idle_age=24, hard_age=65534, priority=1 actions=NORMAL
|
br-int
br-int上掛載了大量的agent來提供各種網路服務,另外負責對發往br-eth1的流量,實現local vlan轉化為外部vlan。
#ovs-ofctl dump-flows br-int
NXST_FLOW reply (xid=0x4):
cookie=0x0, duration=147294.121s, table=0, n_packets=224, n_bytes=33961,
idle_age=13, hard_age=65534, priority=3,in_port=4,dl_vlan=1 actions=mod_vlan_vid:101,NORMAL
cookie=0x0, duration=603538.84s, table=0, n_packets=19, n_bytes=2234,
idle_age=18963, hard_age=65534, priority=2,in_port=4 actions=drop
cookie=0x0, duration=603547.134s, table=0, n_packets=31901,
n_bytes=6419756, idle_age=13, hard_age=65534, priority=1 actions=NORMAL
|
dnsmasq負責提供DHCP服務,繫結到某個特定的名字空間上,每個需要DHCP服務的租戶網路有自己專屬隔離的DHCP服務(圖中的tapXXX和tapWWW上各自監聽了一個dnsmasq)。
路由是L3 agent來實現,每個子網在br-int上有一個埠(qr-YYY和qr-ZZZ,已配置IP,分別是各自內部子網的閘道器),L3 agent繫結到上面。要訪問外部的公共網路,需要通過L3 agent發出,而不是經過int-br-ex到phy-br-ex(實際上並沒有網包從這個veth pair傳輸)。如果要使用外部可見的floating IP,L3 agent仍然需要通過iptables來進行NAT。
每個L3 agent或dnsmasq都在各自獨立的名字空間中,如下圖所示,其中同一租戶的兩個子網都使用了同一個路由器。
對於子網使用不同路由器的情況,多個路由器會在自己獨立的名字空間中。例如要實現兩個租戶的兩個子網的情況,如下圖所示。
這種情況下,網路節點上的名字空間如下圖所示。
br-ex
br-ex要做的事情很簡單,只需要正常轉發即可。
#ovs-ofctl dump-flows br-ex
NXST_FLOW reply (xid=0x4):
cookie=0x0, duration=6770.969s, table=0, n_packets=5411, n_bytes=306944,
idle_age=0, hard_age=65534, priority=0 actions=NORMAL
|
|