Neutron 對虛擬三層網絡的實現是通過其 L3 Agent (neutron-l3-agent)。該 Agent 利用 Linux IP 棧、route 和 iptables 來實現內網內不同網絡內的虛機之間的網絡流量,以及虛機和外網之間網絡流量的路由和轉發。為了在同一個Linux 系統上支持可能的 IP 地址空間重疊,它使用了 Linux network namespace 來提供隔離的轉發上下文。
NameSpace技術
在二層網絡上,VLAN 可以將一個物理交換機分割成幾個獨立的虛擬交換機。類似地,在三層網絡上,Linux network namespace(netns) 可以將一個物理三層網絡分割成幾個獨立的虛擬三層網絡。
Network namespace (netns)從 Linux 2.6.24 版本開始添加,直到 2.6.29 添加完成。每個 netns 擁有獨立的 (virtual)network devices, IP addresses, IP routing tables, /proc/net directory, ports 等等。新創建的 netns 默認只包含 loopback device。除了這個設備,每個 network device,不管是物理的還是虛擬的網卡還是網橋等,都只能存在於一個 netns。而且,連接物理硬件的物理設備只能存在於 root netns。其它普通的網絡設備可以被創建和添加到某個 netns。
添加 network namespace
ip netnas add <network namespace name>
Example:
ip netns add nstest
列表所有 netns
ip netns list
刪除某 netns
ip netns delete <network namespace name>
在 network namespace 中運行命令
ip netns exec <network namespace name> <command>
Example using the namespace from above:
ip netns exec nstest ip addr
添加 virtual interfaces 到 network namespace
ip link add veth-a type veth peer name veth-b #創建一對虛擬網卡veth-a 和 veth-b,兩者由一根虛擬網線連接
將 veth-b 添加到 network namespace
ip link set veth-b netns nstest
設置 vi 的 IP 地址
ip netns exec nstest ip addr add 10.0.0.2/24 dev veth-b
ip netns exec nstest ip link set dev veth-b up
設置默認namespace的vi地址
ip addr add 10.0.0.1/24 dev veth-a
ip link set dev veth-a up
ping
ip netns exec nstest ping 10.0.0.1
PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data.
bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=0.054 ms
查看路由表和 iptbales
ip netns exec nstest route
ip netns exec nstest iptables -L
Iptables
Neutron 主要用到 filter 表和 nat 表,其中, filter 用來實現安全組(Security Group)和 防火牆(FWaas);nat 主要用來實現 router。
iptables其實是個client,供用戶去管理防火牆。相關的請求最后會發送相關內核模塊,如ip_tables。ip_tables內核模塊主要用於組織iptables使用的表,鏈,規則。netfilter是一套技術框架,ip_tables依托於netfilter來注冊各種hooks實現對數據包的具體控制。一些廠商的防火牆,入侵檢測,入侵防御系統什么的基本依托於Netfilter來實現(從事過相關開發)。
NEW,ESTABLISHED,RELATED,INVALID狀態
NEW: conntrack模塊看到的某個連接第一個包,它即將被匹配了。比如,我們看到一個SYN包,是我們所留意的連接的第一個包,就要匹配它。第一個包也可能不是SYN包,但它仍會被認為是NEW狀態。
ESTABLISHED: 已經注意到兩個方向上的數據傳輸,而且會繼續匹配這個連接的包。處於ESTABLISHED狀態的連接是非常容易理解的。只要發送並接到應答,連接就是ESTABLISHED的了。一個連接要從NEW變為ESTABLISHED,只需要接到應答包即可,不管這個包是發往防火牆的,還是要由防火牆轉發的。ICMP的錯誤和重定向等信息包也被看作是ESTABLISHED,只要它們是我們所發出的信息的應答。
RELATED 當一個連接和某個已處於ESTABLISHED狀態的連接有關系時,就被認為是RELATED的了。換句話說,一個連接要想是RELATED的,首先要有一個ESTABLISHED的連接。這個ESTABLISHED連接再產生一個主連接之外的連接,這個新的連接就是RELATED的了,比如ftp的父子鏈接。
INVALID 非以上狀態的包。
iptables自定義連
如果想自行定義規則鏈,可以通過-N參數,然后通過-j/–jump跳轉過來就可以了。
iptables -N 鏈名 iptables ... -j 鏈名
下面我們查看openstack中的router是如何使用iptables的。
首先當路由器創建完成並加入網絡(9.9.9.0/24)之后,我們查看一下它iptable信息。
# Generated by iptables-save v1.6.0 on Tue Jul 18 21:49:49 2017 *nat :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] :neutron-l3-agent-OUTPUT - [0:0] :neutron-l3-agent-POSTROUTING - [0:0] :neutron-l3-agent-PREROUTING - [0:0] :neutron-l3-agent-float-snat - [0:0] :neutron-l3-agent-snat - [0:0] :neutron-postrouting-bottom - [0:0] -A PREROUTING -j neutron-l3-agent-PREROUTING -A OUTPUT -j neutron-l3-agent-OUTPUT -A POSTROUTING -j neutron-l3-agent-POSTROUTING -A POSTROUTING -j neutron-postrouting-bottom -A neutron-l3-agent-PREROUTING -d 169.254.169.254/32 -i qr-+ -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 9697 -A neutron-l3-agent-snat -j neutron-l3-agent-float-snat -A neutron-postrouting-bottom -m comment --comment "Perform source NAT on outgoing traffic." -j neutron-l3-agent-snat COMMIT # Completed on Tue Jul 18 21:49:49 2017 # Generated by iptables-save v1.6.0 on Tue Jul 18 21:49:49 2017 *filter :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :neutron-filter-top - [0:0] :neutron-l3-agent-FORWARD - [0:0] :neutron-l3-agent-INPUT - [0:0] :neutron-l3-agent-OUTPUT - [0:0] :neutron-l3-agent-local - [0:0] :neutron-l3-agent-scope - [0:0] -A INPUT -j neutron-l3-agent-INPUT -A FORWARD -j neutron-filter-top -A FORWARD -j neutron-l3-agent-FORWARD -A OUTPUT -j neutron-filter-top -A OUTPUT -j neutron-l3-agent-OUTPUT -A neutron-filter-top -j neutron-l3-agent-local -A neutron-l3-agent-FORWARD -j neutron-l3-agent-scope -A neutron-l3-agent-INPUT -m mark --mark 0x1/0xffff -j ACCEPT -A neutron-l3-agent-INPUT -p tcp -m tcp --dport 9697 -j DROP -A neutron-l3-agent-scope -o qr-b111bb2e-84 -m mark ! --mark 0x4000000/0xffff0000 -j DROP COMMIT # Completed on Tue Jul 18 21:49:49 2017 # Generated by iptables-save v1.6.0 on Tue Jul 18 21:49:49 2017 *raw :PREROUTING ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :neutron-l3-agent-OUTPUT - [0:0] :neutron-l3-agent-PREROUTING - [0:0] -A PREROUTING -j neutron-l3-agent-PREROUTING -A OUTPUT -j neutron-l3-agent-OUTPUT COMMIT # Completed on Tue Jul 18 21:49:49 2017 # Generated by iptables-save v1.6.0 on Tue Jul 18 21:49:49 2017 *mangle :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] :neutron-l3-agent-FORWARD - [0:0] :neutron-l3-agent-INPUT - [0:0] :neutron-l3-agent-OUTPUT - [0:0] :neutron-l3-agent-POSTROUTING - [0:0] :neutron-l3-agent-PREROUTING - [0:0] :neutron-l3-agent-float-snat - [0:0] :neutron-l3-agent-floatingip - [0:0] :neutron-l3-agent-mark - [0:0] :neutron-l3-agent-scope - [0:0] -A PREROUTING -j neutron-l3-agent-PREROUTING -A INPUT -j neutron-l3-agent-INPUT -A FORWARD -j neutron-l3-agent-FORWARD -A OUTPUT -j neutron-l3-agent-OUTPUT -A POSTROUTING -j neutron-l3-agent-POSTROUTING -A neutron-l3-agent-PREROUTING -j neutron-l3-agent-mark -A neutron-l3-agent-PREROUTING -j neutron-l3-agent-scope -A neutron-l3-agent-PREROUTING -m connmark ! --mark 0x0/0xffff0000 -j CONNMARK --restore-mark --nfmask 0xffff0000 --ctmask 0xffff0000 -A neutron-l3-agent-PREROUTING -j neutron-l3-agent-floatingip -A neutron-l3-agent-PREROUTING -d 169.254.169.254/32 -i qr-+ -p tcp -m tcp --dport 80 -j MARK --set-xmark 0x1/0xffff -A neutron-l3-agent-float-snat -m connmark --mark 0x0/0xffff0000 -j CONNMARK --save-mark --nfmask 0xffff0000 --ctmask 0xffff0000 -A neutron-l3-agent-scope -i qr-b111bb2e-84 -j MARK --set-xmark 0x4000000/0xffff0000 COMMIT # Completed on Tue Jul 18 21:49:49 2017
輸出是分段的,每個段落一個表,*開頭后面跟着表名。
:開頭的行是對鏈匹配次數的總結,后面跟着統計信息,[數據包:字節數]。
后面跟着的是具體規則。
最后跟着COMMIT表示一個表的結束。
然后我們將該路由器關聯一個外部網絡(10.0.99.0/24),我們發現該網絡的所有虛擬機訪問外網時候,會將凡是到達外網絡的數據都進行SNAT為其外部地址10.0.99.2,但是沒有相應的表項導致外網中的虛擬機是無法訪問內部虛擬機的。
root@netagent:~# ip netns exec qrouter-71d8932f-3782-470f-b3a2-f80203f96885 iptables-save # Generated by iptables-save v1.6.0 on Tue Jul 18 22:14:04 2017 *nat :PREROUTING ACCEPT [98:22227] :INPUT ACCEPT [1:325] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] :neutron-l3-agent-OUTPUT - [0:0] :neutron-l3-agent-POSTROUTING - [0:0] :neutron-l3-agent-PREROUTING - [0:0] :neutron-l3-agent-float-snat - [0:0] :neutron-l3-agent-snat - [0:0] :neutron-postrouting-bottom - [0:0] -A PREROUTING -j neutron-l3-agent-PREROUTING -A OUTPUT -j neutron-l3-agent-OUTPUT -A POSTROUTING -j neutron-l3-agent-POSTROUTING -A POSTROUTING -j neutron-postrouting-bottom -A neutron-l3-agent-POSTROUTING ! -i qg-37790cfc-43 ! -o qg-37790cfc-43 -m conntrack ! --ctstate DNAT -j ACCEPT -A neutron-l3-agent-PREROUTING -d 169.254.169.254/32 -i qr-+ -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 9697 -A neutron-l3-agent-snat -j neutron-l3-agent-float-snat -A neutron-l3-agent-snat -o qg-37790cfc-43 -j SNAT --to-source 10.0.99.2 -A neutron-l3-agent-snat -m mark ! --mark 0x2/0xffff -m conntrack --ctstate DNAT -j SNAT --to-source 10.0.99.2 -A neutron-postrouting-bottom -m comment --comment "Perform source NAT on outgoing traffic." -j neutron-l3-agent-snat COMMIT # Completed on Tue Jul 18 22:14:04 2017 # Generated by iptables-save v1.6.0 on Tue Jul 18 22:14:04 2017 *filter :INPUT ACCEPT [26:8892] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :neutron-filter-top - [0:0] :neutron-l3-agent-FORWARD - [0:0] :neutron-l3-agent-INPUT - [0:0] :neutron-l3-agent-OUTPUT - [0:0] :neutron-l3-agent-local - [0:0] :neutron-l3-agent-scope - [0:0] -A INPUT -j neutron-l3-agent-INPUT -A FORWARD -j neutron-filter-top -A FORWARD -j neutron-l3-agent-FORWARD -A OUTPUT -j neutron-filter-top -A OUTPUT -j neutron-l3-agent-OUTPUT -A neutron-filter-top -j neutron-l3-agent-local -A neutron-l3-agent-FORWARD -j neutron-l3-agent-scope -A neutron-l3-agent-INPUT -m mark --mark 0x1/0xffff -j ACCEPT -A neutron-l3-agent-INPUT -p tcp -m tcp --dport 9697 -j DROP -A neutron-l3-agent-scope -o qr-b111bb2e-84 -m mark ! --mark 0x4000000/0xffff0000 -j DROP COMMIT # Completed on Tue Jul 18 22:14:04 2017 # Generated by iptables-save v1.6.0 on Tue Jul 18 22:14:04 2017 *raw :PREROUTING ACCEPT [123:30794] :OUTPUT ACCEPT [0:0] :neutron-l3-agent-OUTPUT - [0:0] :neutron-l3-agent-PREROUTING - [0:0] -A PREROUTING -j neutron-l3-agent-PREROUTING -A OUTPUT -j neutron-l3-agent-OUTPUT COMMIT # Completed on Tue Jul 18 22:14:04 2017 # Generated by iptables-save v1.6.0 on Tue Jul 18 22:14:04 2017 *mangle :PREROUTING ACCEPT [118:29354] :INPUT ACCEPT [23:7908] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] :neutron-l3-agent-FORWARD - [0:0] :neutron-l3-agent-INPUT - [0:0] :neutron-l3-agent-OUTPUT - [0:0] :neutron-l3-agent-POSTROUTING - [0:0] :neutron-l3-agent-PREROUTING - [0:0] :neutron-l3-agent-float-snat - [0:0] :neutron-l3-agent-floatingip - [0:0] :neutron-l3-agent-mark - [0:0] :neutron-l3-agent-scope - [0:0] -A PREROUTING -j neutron-l3-agent-PREROUTING -A INPUT -j neutron-l3-agent-INPUT -A FORWARD -j neutron-l3-agent-FORWARD -A OUTPUT -j neutron-l3-agent-OUTPUT -A POSTROUTING -j neutron-l3-agent-POSTROUTING -A neutron-l3-agent-POSTROUTING -o qg-37790cfc-43 -m connmark --mark 0x0/0xffff0000 -j CONNMARK --save-mark --nfmask 0xffff0000 --ctmask 0xffff0000 -A neutron-l3-agent-PREROUTING -j neutron-l3-agent-mark -A neutron-l3-agent-PREROUTING -j neutron-l3-agent-scope -A neutron-l3-agent-PREROUTING -m connmark ! --mark 0x0/0xffff0000 -j CONNMARK --restore-mark --nfmask 0xffff0000 --ctmask 0xffff0000 -A neutron-l3-agent-PREROUTING -j neutron-l3-agent-floatingip -A neutron-l3-agent-PREROUTING -d 169.254.169.254/32 -i qr-+ -p tcp -m tcp --dport 80 -j MARK --set-xmark 0x1/0xffff -A neutron-l3-agent-float-snat -m connmark --mark 0x0/0xffff0000 -j CONNMARK --save-mark --nfmask 0xffff0000 --ctmask 0xffff0000 -A neutron-l3-agent-mark -i qg-37790cfc-43 -j MARK --set-xmark 0x2/0xffff -A neutron-l3-agent-scope -i qg-37790cfc-43 -j MARK --set-xmark 0x4000000/0xffff0000 -A neutron-l3-agent-scope -i qr-b111bb2e-84 -j MARK --set-xmark 0x4000000/0xffff0000 COMMIT # Completed on Tue Jul 18 22:14:04 2017
Floating Ip
我們將9.9.9.0/24網絡中的虛擬機(9.9.9.3)分配一個floatingIP(10.0.99.3),查看router的iptables-save。
root@netagent:~# ip netns exec qrouter-71d8932f-3782-470f-b3a2-f80203f96885 iptables-save # Generated by iptables-save v1.6.0 on Tue Jul 18 22:23:42 2017 *nat :PREROUTING ACCEPT [48:12000] :INPUT ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] :neutron-l3-agent-OUTPUT - [0:0] :neutron-l3-agent-POSTROUTING - [0:0] :neutron-l3-agent-PREROUTING - [0:0] :neutron-l3-agent-float-snat - [0:0] :neutron-l3-agent-snat - [0:0] :neutron-postrouting-bottom - [0:0] -A PREROUTING -j neutron-l3-agent-PREROUTING -A OUTPUT -j neutron-l3-agent-OUTPUT -A POSTROUTING -j neutron-l3-agent-POSTROUTING -A POSTROUTING -j neutron-postrouting-bottom -A neutron-l3-agent-OUTPUT -d 10.0.99.3/32 -j DNAT --to-destination 9.9.9.3 -A neutron-l3-agent-POSTROUTING ! -i qg-37790cfc-43 ! -o qg-37790cfc-43 -m conntrack ! --ctstate DNAT -j ACCEPT -A neutron-l3-agent-PREROUTING -d 169.254.169.254/32 -i qr-+ -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 9697 -A neutron-l3-agent-PREROUTING -d 10.0.99.3/32 -j DNAT --to-destination 9.9.9.3 -A neutron-l3-agent-float-snat -s 9.9.9.3/32 -j SNAT --to-source 10.0.99.3 -A neutron-l3-agent-snat -j neutron-l3-agent-float-snat -A neutron-l3-agent-snat -o qg-37790cfc-43 -j SNAT --to-source 10.0.99.2 -A neutron-l3-agent-snat -m mark ! --mark 0x2/0xffff -m conntrack --ctstate DNAT -j SNAT --to-source 10.0.99.2 -A neutron-postrouting-bottom -m comment --comment "Perform source NAT on outgoing traffic." -j neutron-l3-agent-snat COMMIT # Completed on Tue Jul 18 22:23:42 2017 # Generated by iptables-save v1.6.0 on Tue Jul 18 22:23:42 2017 *filter :INPUT ACCEPT [608:211608] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :neutron-filter-top - [0:0] :neutron-l3-agent-FORWARD - [0:0] :neutron-l3-agent-INPUT - [0:0] :neutron-l3-agent-OUTPUT - [0:0] :neutron-l3-agent-local - [0:0] :neutron-l3-agent-scope - [0:0] -A INPUT -j neutron-l3-agent-INPUT -A FORWARD -j neutron-filter-top -A FORWARD -j neutron-l3-agent-FORWARD -A OUTPUT -j neutron-filter-top -A OUTPUT -j neutron-l3-agent-OUTPUT -A neutron-filter-top -j neutron-l3-agent-local -A neutron-l3-agent-FORWARD -j neutron-l3-agent-scope -A neutron-l3-agent-INPUT -m mark --mark 0x1/0xffff -j ACCEPT -A neutron-l3-agent-INPUT -p tcp -m tcp --dport 9697 -j DROP -A neutron-l3-agent-scope -o qr-b111bb2e-84 -m mark ! --mark 0x4000000/0xffff0000 -j DROP COMMIT # Completed on Tue Jul 18 22:23:42 2017 # Generated by iptables-save v1.6.0 on Tue Jul 18 22:23:42 2017 *raw :PREROUTING ACCEPT [3155:832499] :OUTPUT ACCEPT [0:0] :neutron-l3-agent-OUTPUT - [0:0] :neutron-l3-agent-PREROUTING - [0:0] -A PREROUTING -j neutron-l3-agent-PREROUTING -A OUTPUT -j neutron-l3-agent-OUTPUT COMMIT # Completed on Tue Jul 18 22:23:42 2017 # Generated by iptables-save v1.6.0 on Tue Jul 18 22:23:42 2017 *mangle :PREROUTING ACCEPT [3150:831059] :INPUT ACCEPT [605:210624] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] :neutron-l3-agent-FORWARD - [0:0] :neutron-l3-agent-INPUT - [0:0] :neutron-l3-agent-OUTPUT - [0:0] :neutron-l3-agent-POSTROUTING - [0:0] :neutron-l3-agent-PREROUTING - [0:0] :neutron-l3-agent-float-snat - [0:0] :neutron-l3-agent-floatingip - [0:0] :neutron-l3-agent-mark - [0:0] :neutron-l3-agent-scope - [0:0] -A PREROUTING -j neutron-l3-agent-PREROUTING -A INPUT -j neutron-l3-agent-INPUT -A FORWARD -j neutron-l3-agent-FORWARD -A OUTPUT -j neutron-l3-agent-OUTPUT -A POSTROUTING -j neutron-l3-agent-POSTROUTING -A neutron-l3-agent-POSTROUTING -o qg-37790cfc-43 -m connmark --mark 0x0/0xffff0000 -j CONNMARK --save-mark --nfmask 0xffff0000 --ctmask 0xffff0000 -A neutron-l3-agent-PREROUTING -j neutron-l3-agent-mark -A neutron-l3-agent-PREROUTING -j neutron-l3-agent-scope -A neutron-l3-agent-PREROUTING -m connmark ! --mark 0x0/0xffff0000 -j CONNMARK --restore-mark --nfmask 0xffff0000 --ctmask 0xffff0000 -A neutron-l3-agent-PREROUTING -j neutron-l3-agent-floatingip -A neutron-l3-agent-PREROUTING -d 169.254.169.254/32 -i qr-+ -p tcp -m tcp --dport 80 -j MARK --set-xmark 0x1/0xffff -A neutron-l3-agent-float-snat -m connmark --mark 0x0/0xffff0000 -j CONNMARK --save-mark --nfmask 0xffff0000 --ctmask 0xffff0000 -A neutron-l3-agent-mark -i qg-37790cfc-43 -j MARK --set-xmark 0x2/0xffff -A neutron-l3-agent-scope -i qg-37790cfc-43 -j MARK --set-xmark 0x4000000/0xffff0000 -A neutron-l3-agent-scope -i qr-b111bb2e-84 -j MARK --set-xmark 0x4000000/0xffff0000 COMMIT # Completed on Tue Jul 18 22:23:42 2017
-A neutron-l3-agent-float-snat -s 9.9.9.3/32 -j SNAT –to-source 10.0.99.3,決定了該虛擬機訪問外網會做SNAT為10.0.99.3,而其他虛擬機依然按照原來方式訪問外網。
-A neutron-l3-agent-PREROUTING -d 10.0.99.3/32 -j DNAT –to-destination 9.9.9.3
Linux IP 棧
Secondary IP
我們看一個路由器的ip信息qg-37790cfc-43接口綁定了浮動ip。
ip netns exec qrouter-71d8932f-3782-470f-b3a2-f80203f96885 ip addr 16: qg-37790cfc-43: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1 link/ether fa:16:3e:51:15:05 brd ff:ff:ff:ff:ff:ff inet 10.0.99.2/24 brd 10.0.99.255 scope global qg-37790cfc-43 valid_lft forever preferred_lft forever inet 10.0.99.3/32 brd 10.0.99.3 scope global qg-37790cfc-43 valid_lft forever preferred_lft forever inet6 fe80::f816:3eff:fe51:1505/64 scope link valid_lft forever preferred_lft forever #解釋 <BROADCAST,MULTICAST,UP,LOWER_UP>:端口的各種狀態 BROADCAST: device can send traffic to all hosts on the link (能夠發廣播) MULTICAST: device can perform and receive multicast packets (能夠發多播) UP: device is functioning (enabled 狀態,可通過 ip * up/down 設置。) LOWER_UP:the state of the Ethernet link(表示線已接上) inet/brd/scope:IP 地址及子網掩碼,廣播地址,作用域 scope:global:valid everywhere
這個interface有兩個靜態 IP 地址。第一個是主要的(primary)IP,第二個是輔助的( secondary) 的 IP。當一個網卡配置了靜態IP后,你可以添加secondary IP 給它。這樣它就擁有了多個 IP 地址了。Secondary IP 不可以通過 DHCP 分配。它所有的IP 地址都關聯到它唯一的一個 MAC 地址上。那為什么需要 secondary IP 地址呢? 路由器有個 Secondary IP 的概念,這個特性可以創建邏輯子網,也就是說在一個物理網口上連接兩個子網,比如這個網口接到一台交換機上,如果這個網口沒有配置Secondary IP的話,那么這台交換機只能連接一個網段的主機,比如 192.168.1.1/24,但是,如果它配置了Secondary IP,那么就可以連接兩個網段的主機,比如 192.168.1.1/24 和 10.0.0.1/24。
Gratuitous ARP
眾所周知,ARP的基本功能就是在以太網環境中,通過目標設備的IP地址,查詢目標設備的MAC地址,以保證通信的順利進行。但由於ARP的廣播、動態學習等特性注定了它不是一種安全的協議,所以在實際應用中,會由於各種各樣的原因使ARP學習失敗,從而影響網絡的互通性,並進而影響用戶的業務穩定運行。整個ARP的體系里基本上就是由ARP Request和Response組成的,Request就是告知對方“我要什么”,而Response是回答“我是什么”。但有些時候也會例外,他們雖然從形式上還是Request和Response的,但它們通常不會不是一問一答的,而是只有其中的一部分,所以通常被稱為免費ARP或無為ARP(Gratuitous ARP)。
Gratuitous ARP在主機啟動的時候,請求自己的IP地址對應的MAC地址。
它常用於三個用途:
Change of L2 address:通告自己改變了 MAC 地址。以 ARP Response 的形式發送廣播,它通常只是為了把自己的ARP信息通告/更新給局域網全體,這種Response不需要別人請求,是自己主動發送的通告。當一個網絡設備的 MAC 地址發生改變時,發送該設備的 Gratuitous ARP,通知所在廣播域內的已經包含該 IP 地址在其 ARP 表中的機器去更新它的 ARP 條目。
Duplicate address detection:重復 MAC 地址檢測。以 ARP Request的形式發送廣播,請求自己的MAC地址,目的是探測局域網中是否有跟自己IP地址相同的主機,也就是常說的IP沖突。發送主機並不需要一定收到此請求的回答。如果收到一個回答,表示網絡中存在與自身IP相同的主機。如果沒有收到應答,則表示本機所使用的IP與網絡中其它主機並不沖突。
Virtual IP:用於一組服務器做 failover 時通知周圍的機器新生效的 IP 地址的 MAC.
Route (Linux 路由表)
route命令用來顯示並設置Linux內核中的網絡路由表,route命令設置的路由主要是靜態路由。要實現兩個不同的子網之間的通信,需要一台連接兩個網絡的路由器,或者同時位於兩個網絡的網關來實現。
route add -net 10.0.0.0 netmask 255.0.0.0 dev eth0 #增加一條經過 eth0 到達 10.0.0.0 的路由
route add -net 10.0.0.0 netmask 255.0.0.0 reject #增加一條屏蔽的路由,目的地址為10.X.X.X將被拒絕。
route del -net 10.0.0.0 netmask 255.0.0.0
route del -net 10.0.0.0 netmask 255.0.0 reject
route del default gw 10.0.36.254
route add default gw 10.0.36.254
基於VRRP的路由高可用
什么是VRRP?
Virtual Redundent Routing Protocol 虛擬冗余路由協議,是一種可以解決這種問題的容錯協議。VRRP協議的目的就是為了解決路由單點故障問題,VRRP通過競選(election)協議來動態的將路由任務交給LAN中虛擬路由器中的某台VRRP路由器。它的原理如下:
在這之前我們先了解一下相關術語:
虛擬路由器:由一個 Master 路由器和多個 Backup 路由器組成。主機將虛擬路由器當作默認網關。
VRID:虛擬路由器的標識,有相同 VRID 的一組路由器構成一個虛擬路由器。通常用(0-255)標識
Master路由器:虛擬路由器中承擔報文轉發任務的路由器。
Backup路由器: Master路由器出現故障時能夠代替 Master路由器工作的路由器。
虛擬 IP:地址虛擬路由器的 IP 地址,一個虛擬路由器可以擁有一個或多個IP 地址。
IP 地址擁有者:接口IP地址與虛擬IP地址相同的路由器被稱為 IP 地址擁有者。
虛擬 MAC 地址:一個虛擬路由器擁有一個虛擬 MAC 地址。虛擬 MAC 地址的格式為 00-00-5E-00-01-{VRID}。通常情況下虛擬路由器回應 ARP 請求使用的是虛擬 MAC 地址,只有虛擬路由器做特殊配置的時候才回應接口的真實 MAC 地址。
priority優先級:VRRP 根據優先級來確定虛擬路由器中每台路由器的地位。用0-255來表示,數字越小優先級越低。VRRP優先級的取值范圍為0到255(數值越大表明優先級越高),可配置的范圍是1到254,優先級0為系統保留給路由器放棄Master位置時候使用,255則是系統保留給IP地址擁有者使用。當路由器為IP地址擁有者時,其優先級始終為255。因此,當虛擬路由器內存在IP地址擁有者時,只要其工作正常,則為Master路由器。
搶占方式:默認,如果 Backup 路由器工作在搶占方式下,當它收到 VRRP 報文后會將自己的優先級與通告報文中的優先級進行比較。如果自己的優先級比當前的 Master 路由器的優先級高就會主動搶占成為 Master 路由器否則將保持 Backup 狀態。
非搶占方式:如果 Backup 路由器工作在非搶占方式下則只要 Master 路由器沒有出現故障Backup 路由器即使隨后被配置了更高的優先級也不會成為Master 路由器。
VRRP協議報文:封裝在IP報文中,發送到分配給 VRRP 的 IP 組播地址。在IP報文頭中,源地址為發送報文接口的主 IP 地址(不是虛擬IP地址),目的地址是224.0.0.18,TTL是255,協議號是112。目前,VRRP協議包括兩個版本:VRRPv2和VRRPv3,VRRPv2僅適用於IPv4網路,VRRPv3適用於IPv4和IPv6兩種網絡。
VRRP 節點三種狀態:初始狀態(Initialize)、活動狀態(Master)、備份狀態(Backup)。其中,只有處於Master狀態的設備才可以轉發那些發送到虛擬IP地址的報文。
然后我們結合上圖來描述一下VRRP的機制。
Device A 和 B 組成一個 VRRP 組,它的虛擬 IP(VIP) 為 10.0.0.3/24。其中,通過選舉機制,A 是 Master Router,B 是 Backup Router。一個 VRRP 組內可以由多個設備,但是只有一個是 Master 設備。注意 Device A 和 B 可以由自己的 IP 地址,VIP 可以和其中的某 IP 相同,也可以不同。
當前,Router A 作為 Master router 向局域網內的機器提供路由服務,Router B 作為 Backup router。它的任務是周期性地接受 A 發出的心跳。在規定的時間段內,如果都沒有收到 A 發出的心跳,則啟動一個選舉過程,重新選出 Master。
局域網內的機器將虛擬路由器當作默認網關,它們僅僅知道這個虛擬路由器的IP 地址 10.0.0.3,而並不知道具體的 Master 路由器的 IP 地址以及 Backup 路由器的IP 地址。它們將自己的缺省路由下一跳地址設置為10.0.0.3。於是,網絡內的主機就通過這個虛擬的路由器來與其它網絡進行通信。如果 Master 路由器壞掉,Backup 路由器將會通過選舉策略選出一個新的 Master 路由器,繼續向網絡內的主機提供路由服務。從而實現網絡內的主機不間斷地與外部網絡進行通信。
它的優勢:
操作簡單:它不需要改變組網情況,也不需要在主機上做任何配置,只需要在相關路由器上配置極少的幾條命令,就能實現下一跳網關的備份,並且不會給主機帶來任何負擔。和其他方法比較起來,VRRP更加能夠滿足用戶的需求。
簡化網絡管理:在具有多播或廣播能力的局域網(如以太網)中,借助 VRRP 能在某台設備出現故障時仍然提供高可靠的缺省鏈路,有效避免單一鏈路發生故障后網絡中斷的問題,而無需修改動態路由協議、路由發現協議等配置信息,也無需修改主機的默認網關配置。
適應性強:VRRP報文封裝在IP報文中,支持各種上層協議。
網絡開銷小:VRRP只定義了一種報文——VRRP通告報文,並且只有處於Master狀態的路由器可以發送VRRP報文。
什么是keepalived ?
Keepalived 是 VRRP 的一個非常好的開源實現,它是一個基於 VRRP 協議來實現的 WEB 服務高可用方案,可以利用其來避免單點故障。在neutron的路由高可用中,需要安裝keepalived 即可。
Keepalived組件如下:
keepalived是模塊化設計,不同模塊負責不同的功能:
core:keepalived的核心;負責主進程的啟動和維護全局配置文件的加載解析等
check:負責healthchecker(健康檢查)包括了各種健康檢查方式以及對應的配置文件的解析
vrrp VRRPD:子進程用來實現VRRP協議
libipfwc iptables(ipchains)庫配置LVS
libipvs*:配置LVS
keepalived進程如下:
Keepalived 使用三個進程,其中 Watchdog 是控制進程,VRRP Stack and Checkers 是它的兩個子進程。
Watchdog 通過心跳機制來確保子進程處於運行狀態。
Checkers:負責真實服務器的健康檢測,用於負載均衡。
VRRP Stack:實現 VRRP 協議,提供 HA。
neutron如何實現?
Neutron L3 HA 的提出就是為了保證 OpenStack 環境三層網絡的高可用性。
QR 和 QG 分別連接內網和外網,這是 router 本來就有的端口;HA 端口是 HA router 才特有的。一個非 HA router,只會存在於一個 Neutron L3 agent 所在的 Network node 中。而一個 HA router 會在多個 Neutron L3 agent 所在的 Network node 里創建 instance,這包括創建相應的 namespace 和端口。每個 HA router instance 里面的 QR 和 QG 都有相同的設備名和 MAC 地址(Media Access Control Address)。
#Master的信息 root@netagent10038219:~# ip netns exec qrouter-23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 28: ha-65bc01fe-af: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 8950 qdisc noqueue state UNKNOWN group default qlen 1 link/ether fa:16:3e:1f:d2:bd brd ff:ff:ff:ff:ff:ff inet 169.254.192.1/18 brd 169.254.255.255 scope global ha-65bc01fe-af valid_lft forever preferred_lft forever inet 169.254.0.1/24 scope global ha-65bc01fe-af valid_lft forever preferred_lft forever inet6 fe80::f816:3eff:fe1f:d2bd/64 scope link valid_lft forever preferred_lft forever 30: qr-fe09d52e-c6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 8950 qdisc noqueue state UNKNOWN group default qlen 1 link/ether fa:16:3e:58:13:ad brd ff:ff:ff:ff:ff:ff inet 1.1.1.1/24 scope global qr-fe09d52e-c6 valid_lft forever preferred_lft forever inet6 fe80::f816:3eff:fe58:13ad/64 scope link nodad valid_lft forever preferred_lft forever 32: qg-21bed7aa-c6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1 link/ether fa:16:3e:a9:28:e7 brd ff:ff:ff:ff:ff:ff inet 10.99.1.101/32 scope global qg-21bed7aa-c6 valid_lft forever preferred_lft forever inet 10.99.1.102/32 scope global qg-21bed7aa-c6 valid_lft forever preferred_lft forever inet 10.99.1.103/24 scope global qg-21bed7aa-c6 valid_lft forever preferred_lft forever inet6 fe80::f816:3eff:fea9:28e7/64 scope link nodad valid_lft forever preferred_lft forever #Slave信息 root@netagent10038220:~# ip netns exec qrouter-23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 26: ha-557abd6c-48: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 8950 qdisc noqueue state UNKNOWN group default qlen 1 link/ether fa:16:3e:3f:75:8d brd ff:ff:ff:ff:ff:ff inet 169.254.192.2/18 brd 169.254.255.255 scope global ha-557abd6c-48 valid_lft forever preferred_lft forever inet6 fe80::f816:3eff:fe3f:758d/64 scope link valid_lft forever preferred_lft forever 29: qr-fe09d52e-c6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 8950 qdisc noqueue state UNKNOWN group default qlen 1 link/ether fa:16:3e:58:13:ad brd ff:ff:ff:ff:ff:ff 32: qg-21bed7aa-c6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1 link/ether fa:16:3e:a9:28:e7 brd ff:ff:ff:ff:ff:ff
Slave 和 Master router instance 的區別在於 Master router instance 的網絡端口上是有 IP 地址的。這些 IP 實際上是 VIP,它們只會存在於 Master router instance 上。每個 router instance 上都有一個 HA 端口,這些端口都有不同的 IP。這些端口是用來進行 VRRP 廣播通信的。每個 router instance 里面都運行着一個 keepalived 進程。Keepalived 是一個實現了 VRRP 的軟件工具,Neutron 利用 keepalived 實現的 L3 HA的。
對於Master 我們查看一下它發的VRRP廣播
root@netagent10038219:~# ip netns exec qrouter-23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b tcpdump -i ha-65bc01fe-af tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on ha-65bc01fe-af, link-type EN10MB (Ethernet), capture size 262144 bytes 05:01:11.336576 IP 169.254.192.1 > 224.0.0.18: VRRPv2, Advertisement, vrid 1, prio 50, authtype none, intvl 2s, length 20 05:01:13.337818 IP 169.254.192.1 > 224.0.0.18: VRRPv2, Advertisement, vrid 1, prio 50, authtype none, intvl 2s, length 20 05:01:15.339083 IP 169.254.192.1 > 224.0.0.18: VRRPv2, Advertisement, vrid 1, prio 50, authtype none, intvl 2s, length 20
HA 端口向廣播地址 224.0.0.18 發送信息。這是由 VRRP 協議規定的。如果 Master router instance 出現故障,不能發出廣播信息,導致 Slave router instance 未在一定的時間內收到廣播信息。剩下的 Slave router instance 會選取出一個來作為新的 Master router instance。這個 instance 會獲取 VIP,從而為 OpenStack 提供三層網絡。雖然提供服務的 router instance 變了,但是 IP 沒有改變,所以從使用者的角度來看,網絡服務沒有發生改變。
vrid 是 HA router 對應的 id,每個 tenant 下面,不同的 router 對應不同的 vrid。需要注意的是,由於 VRRP 協議的限制,vrid 是一個 8 bit 數據。因此每個 tenant 下面,最多只能創建 255 個 HA router。prio 是 instance 的優先級,這個目前是不可配置的,每個 instance 的優先級一樣。authtype 是 instance 之間通信的認證方式,默認是不需要認證。intvl 是廣播之間的間隔時間,默認是 2 秒,這個可以配置。
每個 HA router 一旦被創建,Neutron L3 agent 會為每個 router instance 創建一個 keepalived 進程,在這之前會生成一個 keepalived 的配置文件供 keepalived 的進程使用。
root@netagent10038219:~# ps -aux | grep '23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b' root 4310 0.0 0.8 155892 73080 ? S Mar17 0:05 /usr/bin/python /usr/local/bin/neutron-keepalived-state-change --router_id=23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b --namespace=qrouter-23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b --conf_dir=/var/lib/neutron/ha_confs/23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b --monitor_interface=ha-65bc01fe-af --monitor_cidr=169.254.0.1/24 --pid_file=/var/lib/neutron/external/pids/23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b.monitor.pid --state_path=/var/lib/neutron --user=0 --group=0 root 4810 0.0 0.0 54252 564 ? Ss Mar17 0:59 keepalived -P -f /var/lib/neutron/ha_confs/23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b/keepalived.conf -p /var/lib/neutron/ha_confs/23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b.pid -r /var/lib/neutron/ha_confs/23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b.pid-vrrp root 4811 0.0 0.0 56496 3856 ? S Mar17 2:31 keepalived -P -f /var/lib/neutron/ha_confs/23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b/keepalived.conf -p /var/lib/neutron/ha_confs/23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b.pid -r /var/lib/neutron/ha_confs/23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b.pid-vrrp root 6330 0.0 0.8 140156 71188 ? S Mar28 0:02 /usr/bin/python /usr/local/bin/neutron-ns-metadata-proxy --pid_file=/var/lib/neutron/external/pids/23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b.pid --metadata_proxy_socket=/var/lib/neutron/metadata_proxy --router_id=23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b --state_path=/var/lib/neutron --metadata_port=9697 --metadata_proxy_user=0 --metadata_proxy_group=0 --log-file=neutron-ns-metadata-proxy-23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b.log --log-dir=/var/log/neutron root 28706 0.0 0.0 13080 2544 pts/1 S+ 05:47 0:00 grep --color=auto 23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b root@netagent10038219:/var/lib/neutron/ha_confs/23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b# ls keepalived.conf neutron-keepalived-state-change.log state vrrp_instance VR_1 { state BACKUP interface ha-65bc01fe-af virtual_router_id 1 priority 50 garp_master_delay 60 nopreempt advert_int 2 track_interface { ha-65bc01fe-af } virtual_ipaddress { 169.254.0.1/24 dev ha-65bc01fe-af } virtual_ipaddress_excluded { 1.1.1.1/24 dev qr-fe09d52e-c6 10.99.1.101/32 dev qg-21bed7aa-c6 10.99.1.102/32 dev qg-21bed7aa-c6 10.99.1.103/24 dev qg-21bed7aa-c6 fe80::f816:3eff:fe58:13ad/64 dev qr-fe09d52e-c6 scope link fe80::f816:3eff:fea9:28e7/64 dev qg-21bed7aa-c6 scope link } virtual_routes { 0.0.0.0/0 via 10.99.1.1 dev qg-21bed7aa-c6 } } ======================================================================================== root@netagent10038220:~# ps -aux | grep '23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b' root 4330 0.0 0.8 155896 72840 ? S Mar17 0:04 /usr/bin/python /usr/local/bin/neutron-keepalived-state-change --router_id=23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b --namespace=qrouter-23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b --conf_dir=/var/lib/neutron/ha_confs/23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b --monitor_interface=ha-557abd6c-48 --monitor_cidr=169.254.0.1/24 --pid_file=/var/lib/neutron/external/pids/23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b.monitor.pid --state_path=/var/lib/neutron --user=0 --group=0 root 4882 0.0 0.0 54252 568 ? Ss Mar17 0:59 keepalived -P -f /var/lib/neutron/ha_confs/23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b/keepalived.conf -p /var/lib/neutron/ha_confs/23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b.pid -r /var/lib/neutron/ha_confs/23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b.pid-vrrp root 4883 0.0 0.0 56540 4304 ? S Mar17 1:46 keepalived -P -f /var/lib/neutron/ha_confs/23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b/keepalived.conf -p /var/lib/neutron/ha_confs/23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b.pid -r /var/lib/neutron/ha_confs/23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b.pid-vrrp root 25801 0.0 0.0 13080 2548 pts/0 S+ 05:48 0:00 grep --color=auto 23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b root@netagent10038220:/var/lib/neutron/ha_confs/23d7334d-a55f-4b4b-9dfa-4d1ee4b3080b# ls keepalived.conf neutron-keepalived-state-change.log state vrrp_instance VR_1 { state BACKUP interface ha-557abd6c-48 virtual_router_id 1 priority 50 garp_master_delay 60 nopreempt advert_int 2 track_interface { ha-557abd6c-48 } virtual_ipaddress { 169.254.0.1/24 dev ha-557abd6c-48 } virtual_ipaddress_excluded { 1.1.1.1/24 dev qr-fe09d52e-c6 10.99.1.101/32 dev qg-21bed7aa-c6 10.99.1.102/32 dev qg-21bed7aa-c6 10.99.1.103/24 dev qg-21bed7aa-c6 fe80::f816:3eff:fe58:13ad/64 dev qr-fe09d52e-c6 scope link fe80::f816:3eff:fea9:28e7/64 dev qg-21bed7aa-c6 scope link } virtual_routes { 0.0.0.0/0 via 10.99.1.1 dev qg-21bed7aa-c6 } }
總的來說,要使用 HA router,首先必須有多個 Neutron L3 agent 在不同的 Network node 上運行。一旦創建了一個 HA router,Neutron 會通過多個 L3 agent 創建相應的 namespace 和端口,這樣就有了這個 HA router 的多個 instance。同時,L3 agent 還會創建 keepalived 進程,每個 keepalived 進程都有 router 的全部信息。這樣,每個 Network node 上都有 HA router 的一個 instance 和管理這個 router instance 的 keepalived 進程。
當一切就緒之后,這些 router instance 會進行一次選舉,勝出的作為 Master instance,剩下的作為 Slave instance。由於所有的 router instance 的優先級都是一樣的,選舉的結果是隨機的。也就是說,如果創建多個 HA router,這些 router 的 Master instance 可能分布在多個 Network node 上。
選舉結束后,Master router instance 負責提供 L3 網絡服務,並同時向其他的 Slave router instance 發廣播報告自身的狀況。一旦由於各種原因,廣播中斷,Slave router instance 會重新選舉出新的 Master router instance,繼續提供 L3 網絡服務,並同時發送廣播報告自身的狀況。
DVR分布式路由的實現
DVR的架構
網絡層:
架構:
DVR的配置與試驗
上圖是我搭建的部署環境(你可以將Network Server與Controller Node放在一起),對於DVR來說我們需要操作如下:
控制節點:
neutron.conf [DEFAULT] router_distributed = True
網絡節點:
openvswitch_agent.ini [agent] enable_distributed_routing = True l3_agent.ini [DEFAULT] agent_mode = dvr_snat
計算節點:
yum install openstack-neutron systemctl enable neutron-l3-agent.service openvswitch_agent.ini [agent] enable_distributed_routing = True l3_agent.ini [DEFAULT] interface_driver = neutron.agent.linux.interface.OVSInterfaceDriver agent_mode = dvr
然后重啟以下服務:
控制節點:systemctl restart neutron-server 計算節點:systemctl restart neutron-openvswitch-agent systemctl start neutron-l3-agent 網絡節點:systemctl restart neutron-openvswitch-agent systemctl restart neutron-l3-agent
為了演示DVR我們創建外部網絡
[root@controller ~]# neutron net-create --shared --provider:physical_network external --provider:network_type flat external_net [root@controller ~]# neutron subnet-create --name external_net --allocation-pool start=123.4.4.10,end=123.4.4.50 --dns-nameserver 123.4.4.1 --gateway 123.4.4.1 external_net 123.4.4.0/24 [root@controller ~]# neutron net-update external_net --router:external
在下面實現之前要注意:
當虛擬機創建落在計算機點后,才會在該計算機節點出現qrouter的namespace
當router設置網關后,才會出現snat namespace
當關聯floating ip 才會在計算機點出現fixed ip 的namespace
創建路由器
如果我們選擇了外部網絡后,在網絡節點就會出現snat namespace
[root@netagent ~]# ip netns list snat-851e3ae1-1b10-41ed-b215-f0e5dfd7a46a [root@netagent ~]# ip netns exec snat-851e3ae1-1b10-41ed-b215-f0e5dfd7a46a ifconfig lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 0 (Local Loopback) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 qg-b683d547-5f: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 123.4.4.14 netmask 255.255.255.0 broadcast 123.4.4.255 inet6 fe80::f816:3eff:fe88:bdc7 prefixlen 64 scopeid 0x20<link> ether fa:16:3e:88:bd:c7 txqueuelen 1000 (Ethernet) RX packets 5 bytes 332 (332.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 13 bytes 1074 (1.0 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
fixed IP的南北向流量
創建內部網絡6.6.6.0/24和虛擬機6.6.6.5,虛擬機落在計算節點2,我們看到在這個節點出現了qrouter-namespace,同時網絡節點也出現了qrouter-namespace,這兩個網絡接口信息一樣,同時snat-namespace也多了一個網口。
[root@com2 ~]# ip netns list qrouter-851e3ae1-1b10-41ed-b215-f0e5dfd7a46a [root@com2 ~]# ip netns exec qrouter-851e3ae1-1b10-41ed-b215-f0e5dfd7a46a ifconfig lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 0 (Local Loopback) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 qr-b452f7b9-bc: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1450 inet 6.6.6.1 netmask 255.255.255.0 broadcast 6.6.6.255 inet6 fe80::f816:3eff:fe99:3c29 prefixlen 64 scopeid 0x20<link> ether fa:16:3e:99:3c:29 txqueuelen 1000 (Ethernet) RX packets 10 bytes 1076 (1.0 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 10 bytes 864 (864.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 [root@netagent ~]# ip netns list snat-851e3ae1-1b10-41ed-b215-f0e5dfd7a46a qrouter-851e3ae1-1b10-41ed-b215-f0e5dfd7a46a [root@netagent ~]# ip netns exec snat-851e3ae1-1b10-41ed-b215-f0e5dfd7a46a ifconfig lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 0 (Local Loopback) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 qg-b683d547-5f: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 123.4.4.14 netmask 255.255.255.0 broadcast 123.4.4.255 inet6 fe80::f816:3eff:fe88:bdc7 prefixlen 64 scopeid 0x20<link> ether fa:16:3e:88:bd:c7 txqueuelen 1000 (Ethernet) RX packets 19 bytes 1324 (1.2 KiB) RX errors 0 dropped 1 overruns 0 frame 0 TX packets 13 bytes 1074 (1.0 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 sg-d722c249-c5: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1450 inet 6.6.6.3 netmask 255.255.255.0 broadcast 6.6.6.255 inet6 fe80::f816:3eff:fef5:93ba prefixlen 64 scopeid 0x20<link> ether fa:16:3e:f5:93:ba txqueuelen 1000 (Ethernet) RX packets 22 bytes 1500 (1.4 KiB) RX errors 0 dropped 2 overruns 0 frame 0 TX packets 15 bytes 1210 (1.1 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
在虛機沒有floating ip的情況下訪問外網,從虛機發出的包會首先到計算節點的qrouter-851e3ae1-1b10-41ed-b215-f0e5dfd7a46a,丟給網關6.6.6.1/24,然后匹配table 101058049,我們看到會交給6.6.6.3的地址,它正是snat-namespace新出現的網口sg-d722c249-c5地址。
[root@com2 ~]# ip netns exec qrouter-851e3ae1-1b10-41ed-b215-f0e5dfd7a46a ip rule 0: from all lookup local 32766: from all lookup main 32767: from all lookup default 101058049: from 6.6.6.1/24 lookup 101058049 [root@com2 ~]# ip netns exec qrouter-851e3ae1-1b10-41ed-b215-f0e5dfd7a46a ip route list table 101058049 default via 6.6.6.3 dev qr-b452f7b9-bc [root@netagent ~]# ip netns exec snat-851e3ae1-1b10-41ed-b215-f0e5dfd7a46a iptables -nvL -t nat Chain neutron-l3-agent-snat (1 references) pkts bytes target prot opt in out source destination 0 0 SNAT all -- * qg-b683d547-5f 0.0.0.0/0 0.0.0.0/0 to:123.4.4.14
總之,虛擬機通過計算節點的qrouter-namespace再到網絡節點的snat-namespace,而外網返回的數據會通過網絡節點的snat-namespace和qrouter-namespace到計算節點的虛擬機。
整個流程如下所示:
floatingip的南北向流量
我們對虛擬機6.6.6.5綁定一個floatingip如下:
我們看到虛擬機所在的節點多出了fip-namespace,同時我們看到qrouter-namespace有很多變化。虛擬機6.6.6.5ping外網時候,它的數據的首先查找主表main,沒有匹配項后,就會匹配from 6.6.6.5 lookup 16,而不會匹配from 6.6.6.1/24 lookup 101058049 。在table16,我們看到數據想通過qrouter-namespace的rfp-851e3ae1-1到達169.254.106.115,數據轉發到rfp-851e3ae1-1接口后,qrouter-namespace對其作了SNAT,neutron-l3-agent-float-snat -s 6.6.6.5/32 -j SNAT –to-source 123.4.4.16,也就是數據從rfp-851e3ae1-1發出后的源地址為123.4.4.16。qrouter-namespace的rfp-851e3ae1-1與fip-namespace的fpr-851e3ae1-1是veth對,此時數據就到達了fip-namespace。我們看一下fip-namespace路由表,數據會轉發到fg-9b5bb134-fa接口到達外網。
外網數據返回時候,以 123.4.4.16/32作為目的地址發給fip-namespace的fg-9b5bb134-fa,根據路由表會通過fpr-851e3ae1-1發給網關169.254.106.114,也就是qrouter-namespace的rfp-851e3ae1-1接口地址,到達該接口,qrouter-namespace作DNAT,將123.4.4.16/32變為6.6.6.5/32。neutron-l3-agent-PREROUTING -d 123.4.4.16/32 -j DNAT –to-destination 6.6.6.5,然后查主表如何到達6.6.6.5,根據路由表,我們發現數據到達了 qr-b452f7b9-bc發出,之后就會轉發到br-int再到虛機。
[root@com2 ~]# ip netns list fip-49ca86bb-afe9-4c6f-a67f-5399f57b851d qrouter-851e3ae1-1b10-41ed-b215-f0e5dfd7a46a [root@com2 ~]# ip netns exec qrouter-851e3ae1-1b10-41ed-b215-f0e5dfd7a46a ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: rfp-851e3ae1-1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether ce:61:44:bd:66:1e brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 169.254.106.114/31 scope global rfp-851e3ae1-1 valid_lft forever preferred_lft forever inet 123.4.4.16/32 brd 123.4.4.16 scope global rfp-851e3ae1-1 valid_lft forever preferred_lft forever inet6 fe80::cc61:44ff:febd:661e/64 scope link valid_lft forever preferred_lft forever 15: qr-b452f7b9-bc: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc pfifo_fast state UNKNOWN qlen 1000 link/ether fa:16:3e:99:3c:29 brd ff:ff:ff:ff:ff:ff inet 6.6.6.1/24 brd 6.6.6.255 scope global qr-b452f7b9-bc valid_lft forever preferred_lft forever inet6 fe80::f816:3eff:fe99:3c29/64 scope link valid_lft forever preferred_lft forever [root@com2 ~]# ip netns exec qrouter-851e3ae1-1b10-41ed-b215-f0e5dfd7a46a ip rule 0: from all lookup local 32766: from all lookup main 32767: from all lookup default 57481: from 6.6.6.5 lookup 16 101058049: from 6.6.6.1/24 lookup 101058049 [root@com2 ~]# ip netns exec qrouter-851e3ae1-1b10-41ed-b215-f0e5dfd7a46a ip route list table main 6.6.6.0/24 dev qr-b452f7b9-bc proto kernel scope link src 6.6.6.1 169.254.106.114/31 dev rfp-851e3ae1-1 proto kernel scope link src 169.254.106.114 [root@com2 ~]# ip netns exec qrouter-851e3ae1-1b10-41ed-b215-f0e5dfd7a46a route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 6.6.6.0 0.0.0.0 255.255.255.0 U 0 0 0 qr-b452f7b9-bc 169.254.106.114 0.0.0.0 255.255.255.254 U 0 0 0 rfp-851e3ae1-1 [root@com2 ~]# ip netns exec qrouter-851e3ae1-1b10-41ed-b215-f0e5dfd7a46a ip route list table 16 default via 169.254.106.115 dev rfp-851e3ae1-1 [root@com2 ~]# ip netns exec qrouter-851e3ae1-1b10-41ed-b215-f0e5dfd7a46a iptables-save ..... -A neutron-l3-agent-OUTPUT -d 123.4.4.16/32 -j DNAT --to-destination 6.6.6.5 -A neutron-l3-agent-POSTROUTING ! -i rfp-851e3ae1-1 ! -o rfp-851e3ae1-1 -m conntrack ! --ctstate DNAT -j ACCEPT -A neutron-l3-agent-PREROUTING -d 169.254.169.254/32 -i qr-+ -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 9697 -A neutron-l3-agent-PREROUTING -d 123.4.4.16/32 -j DNAT --to-destination 6.6.6.5 -A neutron-l3-agent-float-snat -s 6.6.6.5/32 -j SNAT --to-source 123.4.4.16 -A neutron-l3-agent-snat -j neutron-l3-agent-float-snat -A neutron-postrouting-bottom -m comment --comment "Perform source NAT on outgoing traffic." -j neutron-l3-agent-snat COMMIT [root@com2 ~]# ip netns exec fip-49ca86bb-afe9-4c6f-a67f-5399f57b851d ifconfig fg-9b5bb134-fa: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1450 inet 123.4.4.17 netmask 255.255.255.0 broadcast 123.4.4.255 inet6 fe80::f816:3eff:fe5d:43b7 prefixlen 64 scopeid 0x20<link> ether fa:16:3e:5d:43:b7 txqueuelen 1000 (Ethernet) RX packets 3 bytes 84 (84.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 10 bytes 864 (864.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 fpr-851e3ae1-1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 169.254.106.115 netmask 255.255.255.254 broadcast 0.0.0.0 inet6 fe80::b8fe:64ff:fe79:1608 prefixlen 64 scopeid 0x20<link> ether ba:fe:64:79:16:08 txqueuelen 1000 (Ethernet) RX packets 7 bytes 738 (738.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 7 bytes 738 (738.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 0 (Local Loopback) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 [root@com2 ~]# ip netns exec fip-49ca86bb-afe9-4c6f-a67f-5399f57b851d route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 123.4.4.1 0.0.0.0 UG 0 0 0 fg-9b5bb134-fa 123.4.4.0 0.0.0.0 255.255.255.0 U 0 0 0 fg-9b5bb134-fa 123.4.4.16 169.254.106.114 255.255.255.255 UGH 0 0 0 fpr-851e3ae1-1 169.254.106.114 0.0.0.0 255.255.255.254 U 0 0 0 fpr-851e3ae1-1 [root@com2 ~]# ip netns exec fip-49ca86bb-afe9-4c6f-a67f-5399f57b851d ip route list table main default via 123.4.4.1 dev fg-9b5bb134-fa 123.4.4.0/24 dev fg-9b5bb134-fa proto kernel scope link src 123.4.4.17 123.4.4.16 via 169.254.106.114 dev fpr-851e3ae1-1 169.254.106.114/31 dev fpr-851e3ae1-1 proto kernel scope link src 169.254.106.115
東西流量
我們又創建了一個子網192.168.1.0/24,虛擬機192.168.1.5在計算節點1,在計算機點1也會出現qrouter-namespace
[root@com1 ~]# ip netns list qrouter-851e3ae1-1b10-41ed-b215-f0e5dfd7a46a [root@com1 ~]# ip netns exec qrouter-851e3ae1-1b10-41ed-b215-f0e5dfd7a46a ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 15: qr-b452f7b9-bc: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc pfifo_fast state UNKNOWN qlen 1000 link/ether fa:16:3e:99:3c:29 brd ff:ff:ff:ff:ff:ff inet 6.6.6.1/24 brd 6.6.6.255 scope global qr-b452f7b9-bc valid_lft forever preferred_lft forever inet6 fe80::f816:3eff:fe99:3c29/64 scope link valid_lft forever preferred_lft forever 18: qr-ff78f72b-98: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc pfifo_fast state UNKNOWN qlen 1000 link/ether fa:16:3e:a8:f8:fa brd ff:ff:ff:ff:ff:ff inet 192.168.1.1/24 brd 192.168.1.255 scope global qr-ff78f72b-98 valid_lft forever preferred_lft forever inet6 fe80::f816:3eff:fea8:f8fa/64 scope link valid_lft forever preferred_lft forever
我們用虛擬機192.168.1.5 ping 6.6.6.5。首先會查詢路由表,將包發送到網關192.168.1.1。那么會首先會發送192.168.1.1的arp請求。arp請求會發送到br-int上,192.168.1.5 的portid為b452f7b9-bc4d-464d-8dca-fa2396bfba85,對應的br-int上是Port “qvob452f7b9-bc”
而端口qvo45b153f7-40是屬於vlan 2的,qr-b452f7b9-bc也是屬於vlan2的,arp廣播包會轉發到”qr-b452f7b9-bc”和”patch-tun”。而”qr-b452f7b9-bc”是com2的qrouter-851e3ae1-1b10-41ed-b215-f0e5dfd7a46a路由接口,擁有網關地址“192.168.1.1”
對於”patch-tun”,之后會發送到“br-tun”,我們看看“br-tun”
cookie=0xbe2941571871a27c, duration=13079.754s, table=1, n_packets=1, n_bytes=42, idle_age=13078, priority=3,arp,dl_vlan=2,arp_tpa=192.168.1.1 actions=drop
cookie=0xbe2941571871a27c, duration=13079.552s, table=1, n_packets=1, n_bytes=42, idle_age=13078, priority=3,arp,dl_vlan=5,arp_tpa=6.6.6.1 actions=drop
發現數據包會由table=0,轉給table=1,對於arp采取丟棄的方式。
虛擬機192.168.1..5 ,當獲取到了192.168.1.1的MAC地址后,會發出如下的包:
Dest IP: 6.6.6.5
Souce IP: 192.168.1.5
Dest MAC: MAC of 192.168.1.1
Source MAC: MAC of 192.168.1.5
執行命令查看ip netns exec qrouter-851e3ae1-1b10-41ed-b215-f0e5dfd7a46a ip rule
0: from all lookup local
32766: from all lookup main
32767: from all lookup default
查看main
ip netns exec qrouter-851e3ae1-1b10-41ed-b215-f0e5dfd7a46a ip route list table main
6.6.6.0/24 dev qr-b452f7b9-bc proto kernel scope link src 6.6.6.1
192.168.1.0/24 dev qr-ff78f72b-98 proto kernel scope link src 192.168.1.1
在main表中滿足以下路由:
6.6.6.0/24 dev qr-b452f7b9-bc proto kernel scope link src 6.6.6.1
因此會從qr-b452f7b9-bc 轉發出去。
之后需要去查詢6.6.6.5 的MAC地址, MAC是由neutron使用靜態ARP的方式設定的:
ip netns exec qrouter-851e3ae1-1b10-41ed-b215-f0e5dfd7a46a ip nei
6.6.6.5 dev qr-ff78f72b-98 lladdr fa:16:3e:23:77:1c PERMANENT
由於Neutron知道所有虛機的信息,因此他可以事先設定好靜態ARP。
至此,我們的ICMP包會變成以下形式從qr-b452f7b9-bc 轉發出去:
Dest IP: 6.6.6.5
Souce IP: 192.168.1.5
Dest MAC: MAC of 6.6.6.5
Source MAC: MAC of 192.168.1.5
當包轉發到”br-tun”后,開始查詢openflow表。
ovs-ofctl show br-tun 可以查看端口狀態
首先我們看一下br-tun的flowtable,首先會進入table 0,由於包是從br-int發過來的,因此in_port是patch-int(1),之后會查詢表1,這張表中會丟棄目標地址是interface_distributed接口的ARP和目的MAC是interface_distributed的包。以防止虛機發送給本地路由器的包被轉發到網絡中。
我們的ICMP包會命中一下flow,它會把源MAC地址改為全局唯一和計算節點綁定的MAC(fa:16:3f:88:30:58):
cookie=0xbe2941571871a27c, duration=13079.754s, table=1, n_packets=1, n_bytes=42, idle_age=13078, priority=3,arp,dl_vlan=2,arp_tpa=192.168.1.1 actions=drop
cookie=0xbe2941571871a27c, duration=13079.552s, table=1, n_packets=1, n_bytes=42, idle_age=13078, priority=3,arp,dl_vlan=5,arp_tpa=6.6.6.1 actions=drop
cookie=0xbae18ea66f2bd595, duration=69678.476s, table=1, n_packets=0, n_bytes=0, idle_age=65534, hard_age=65534, priority=2,dl_vlan=2,dl_dst=fa:16:3e:99:3c:29 actions=drop
cookie=0xbae18ea66f2bd595, duration=16219.966s, table=1, n_packets=0, n_bytes=0, idle_age=16219, priority=2,dl_vlan=5,dl_dst=fa:16:3e:a8:f8:fa actions=drop
cookie=0xbae18ea66f2bd595, duration=69678.454s, table=1, n_packets=4, n_bytes=440, idle_age=65534, hard_age=65534, priority=1,dl_vlan=2,dl_src=fa:16:3e:99:3c:29 actions=mod_dl_src:fa:16:3f:88:30:58,resubmit(,2)
cookie=0xbae18ea66f2bd595, duration=16219.961s, table=1, n_packets=4, n_bytes=440, idle_age=16218, priority=1,dl_vlan=5,dl_src=fa:16:3e:a8:f8:fa actions=mod_dl_src:fa:16:3f:88:30:58,resubmit(,2)
繼續查詢流表2,表2是VXLAN表,如果是廣播包就會查詢表22,如果是單播包就查詢表20:
cookie=0xbae18ea66f2bd595, duration=79697.638s, table=2, n_packets=0, n_bytes=0, idle_age=65534, hard_age=65534, priority=0,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,20)
cookie=0xbae18ea66f2bd595, duration=79697.637s, table=2, n_packets=120088, n_bytes=5057540, idle_age=1, hard_age=65534, priority=0,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,22)
ICMP包是單播包,因此會查詢表20,由於開啟了L2 pop功能,在表20中會事先學習到應該轉發到哪個VTEP
cookie=0xbae18ea66f2bd595, duration=15286.730s, table=20, n_packets=0, n_bytes=0, idle_age=15286, priority=2,dl_vlan=2,dl_dst= fa:16:3e:23:77:1c actions=strip_vlan,set_tunnel:0x62,output:2
此時包會變成如下形式:
Dest IP: 6.6.6.5
Souce IP: 192.168.1.5
Dest MAC: MAC of 6.6.6.5
Source MAC: 16:3f:88:30:58
之后包會從port 2發出。
數據包到達com2上查詢br-tun的流表:
ovs-ofctl show br-tun 可以查看端口狀態
在table0中可以看到,如果包是從外部發來的就會去查詢表4:
ovs-ofctl dump-flows br-tun | grep “table=0”
cookie=0x83d99e19c90a76fc, duration=10376.919s, table=0, n_packets=6, n_bytes=580, idle_age=6185, priority=1,in_port=2 actions=resubmit(,4)
在表4中,會將tun_id對應的改為本地vlan id,之后查詢表9:
cookie=0x83d99e19c90a76fc, duration=5190.158s, table=4, n_packets=0, n_bytes=0, idle_age=5190, priority=1,tun_id=0x42 actions=mod_vlan_vid:5,resubmit(,9)
在表9中,如果發現包的源地址是全局唯一並與計算節點綁定的MAC地址,就將其轉發到br-int:
cookie=0x83d99e19c90a76fc, duration=21043.043s, table=9, n_packets=0, n_bytes=0, idle_age=21043, priority=1,dl_src=16:3f:88:30:58 actions=output:1
由於我們的源MAC為16:3f:88:30:58,我們的ICMP包就被轉發到了br-int,之后查詢br-int的流表:
ovs-ofctl dump-flows br-int
cookie=0xa0e2bd57839cefda, duration=21258.165s, table=0, n_packets=0, n_bytes=0, idle_age=21258, priority=2,in_port=1,dl_src=16:3f:88:30:58 actions=resubmit(,1)
在表1中,事先設定好了flow,如果目的MAC是發送給虛擬機6.6.6.5,就將源MAC改為network 2的網關MAC地址:
cookie=0xa0e2bd57839cefda, duration=5401.439s, table=1, n_packets=0, n_bytes=0, idle_age=5401, priority=4,dl_vlan=3,dl_dst=16:3f:88:30:58 actions=strip_vlan,mod_dl_src:fa:16:3e:99:3c:29,output:15
經過br-int的流表后,包會變成如下形式:
Dest IP: 6.6.6.5
Souce IP: 192.168.1.5
Dest MAC: MAC of 6.6.6.5
Source MAC:fa:16:3e:99:3c:29(6.6.6.0/24的網關MAC地址)
DHCP服務
neutron dhcp為租戶網絡提供DHCP服務,即IP地址動態分配,另外還會提供metadata請求服務。
3個主要的部件:
DHCP agent scheduler:負責DHCP agent與network的調度。
DHCP agent:為租戶網絡提供DHCP的功能,提供metadata request服務。
DHCP driver:即dnsmasq,用於管理DHCP server。
Dnsmasq 是被 Neutron 用來提供 DHCP 和 DNS 服務的一個開源程序,即DHCP driver部分。它提供 DNS 緩存和 DHCP 服務功能。作為域名解析服務器(DNS),dnsmasq可以通過緩存 DNS 請求來提高對訪問過的網址的連接速度。作為DHCP 服務器,dnsmasq 可以為局域網電腦提供內網ip地址和路由。DNS和DHCP兩個功能可以同時或分別單獨實現。dnsmasq輕量且易配置,適用於主機較少的網絡。
根據整個dhcp處理的流程,dhcp模塊主要由Neutron api、core plugin(如linux bridge plugin,ovs plugin等)、dhcp agent scheduler、dhcp agent、dhcp driver(dnsmasq)構成。
對應架構圖中數字,有以下幾個接口:
1.network/subnet/port的操作
2.agent management/agent scheduler的操作
3.network/subnet/port操作會發送rpc請求到dhcp agent。
4.agentscheduler db發送rpc請求到dhcp agent。
5.dhcp agent通過DhcpPluginApi發送rpc請求到core plugin,操作相應的數據庫。
6.dhcp agent調用dhcp driver進行dhcp相關操作。
虛機獲取固定IP (Fixed IP)主要分為兩個步驟:
在創建虛機過程中,Neutron 隨機生成 MAC 和 從配置數據中分配一個固定IP 地址,並保存到 Dnsmasq 的 hosts 文件中,讓 Dnsmasq 做好准備。
虛機在啟動時向 Dnsmasq 獲取 IP 地址
紅色為創建虛擬機的數據流
綠色為虛擬機啟動的數據流
創建虛機時的數據流
Controller 節點上的 Neutron Server 接到該請求后,會開始下面的過程:
步驟 2 ~ 6:Neutron Server 生成 MAC 和 IP。 其中 MAC 是由任意數組成的;Fixed IP 是從保存在數據庫中的管理員配置的網絡和地址數據生成的。
步驟 7 ~ 10: 調用 L3 Agent 和 OVS 執行一些操作。
步驟 12 ~ 14:通過 AMQP 的 cast 消息給 Neutron 節點上的 DHCP Agent,告訴它 Port 創建結束以及 新分配的 Port 的數據。
步驟 13:返回Port 給 nova-compute。
步驟 15:Neturon 節點上的 DHCP Agent 根據接收到的 Port 創建完成通知,重新生成 Dnsmasq 的 hosts 文件,然后讓 Dnsmasq 重新加載該文件。Nova 拿到 Port 的數據后,會寫入虛機的 libvirt.xml 文件。