學習 Neutron 系列文章:
(2)Neutron OpenvSwitch + VLAN 虛擬網絡
(3)Neutron OpenvSwitch + GRE/VxLAN 虛擬網絡
(4)Neutron OVS OpenFlow 流表 和 L2 Population
(9)Neutron FWaas 和 Nova Security Group
(10)Neutron VPNaas
(11)Neutron DVR
(12)Neutron VRRP
OVS bridge 有兩種模式:“normal” 和 “flow”。“normal” 模式的 bridge 同普通的 Linux 橋,而 “flow” 模式的 bridge 是根據其流表(flow tables) 來進行轉發的。Neutron 使用兩種 OVS bridge:br-int 和 br-tun。其中,br-int 是一個 “normal” 模式的虛擬網橋,而 br-tun 是 “flow” 模式的,它比 br-int 復雜得多。
1. 基礎知識
1.1 OpenFlow 結構、流表和數據包處理
下面左圖是 Open vSwitch 中流表的結構。右圖這個流程圖詳細描述了數據包流通過一個 OpenFlow 交換機的過程。
更詳細的描述請參見這里。
1.2 ARP Proxy
Proxy ARP 就是通過一個主機(通常是Router)來作為指定的設備對另一個設備作出 ARP 的請求進行應答。
最主要的一個優點就是能夠在不影響其他router的路由表的情況下在網絡上添加一個新的router,這樣使得子網的變化對主機是透明的。
proxy ARP應該使用在主機沒有配置默認網關或沒有任何路由策略的網絡上
缺點:
1.增加了某一網段上 ARP 流量
2.主機需要更大的 ARP table 來處理IP地址到MAC地址的映射
3.安全問題,比如 ARP 欺騙(spoofing)
4.不會為不使用 ARP 來解析地址的網絡工作
5.不能夠概括和推廣網絡拓撲
來源:百度百科
2. 不使用 ARP Responder 和 DVR 時 br-tun 中的流表(flow tables)
OpenStack 中,Neutron 作為 OVS 的 Controller,向 OVS 發出管理 tunnel port 的指令,以及提供流表。
2.1 流表分析
Neutron 定義了多種流表。以下面的配置(配置了 GRE 和 VXLAN 兩種 tunnel types)為例:
1(patch-int): addr:a6:d4:dd:37:00:52 2(vxlan-0a000127): addr:36:ec:de:b4:b9:6b {in_key=flow, local_ip="10.0.1.31", out_key=flow, remote_ip="10.0.1.39"} 計算節點2 3(vxlan-0a000115): addr:4a:c8:21:3c:3f:f1 {in_key=flow, local_ip="10.0.1.31", out_key=flow, remote_ip="10.0.1.21"} 網絡節點 4(gre-0a000115): addr:4a:8b:0f:9d:59:52 {in_key=flow, local_ip="10.0.1.31", out_key=flow, remote_ip="10.0.1.21"} 網絡節點 5(gre-0a000127): addr:aa:58:6d:0a:f7:6a {in_key=flow, local_ip="10.0.1.31", out_key=flow, remote_ip="10.0.1.39"} 計算節點2
其中,10.0.1.31 是計算節點1, 10.0.1.21 是網絡節點, 10.0.1.39 是計算節點2。
計算節點1 上 ML2 Agent 啟動后的 br-tun 的 flows:
表號 | 用途 | 例子 |
0 |
table=0, priority=1,in_port=3 actions=resubmit(,4) //從網絡節點來的,轉 4,結果被丟棄 table=0, priority=1,in_port=4 actions=resubmit(,3) //從網絡節點來的,轉 3
table=0, priority=1,in_port=2 actions=resubmit(,4) //從計算節點來的,轉 4,結果被丟棄 table=0, priority=1,in_port=1 actions=resubmit(,2) //從虛機來的,轉 2 |
|
DVR_PROCESS = 1 | handle packets coming from patch_int unicasts go to table UCAST_TO_TUN where remote addresses are learnt | 用於 DVR |
PATCH_LV_TO_TUN = 2 |
table=2, priority=0,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,20) //單播包,轉 20 |
|
GRE_TUN_TO_LV = 3 | table=3, priority=1,tun_id=0x4 actions=mod_vlan_vid:1,resubmit(,10) //將 tun_id 為 4 的,修改 vlan id 為1,轉 10 處理 |
|
VXLAN_TUN_TO_LV = 4 | table=4, priority=0 actions=drop //丟棄 | |
DVR_NOT_LEARN = 9 | 用於 DVR | |
LEARN_FROM_TUN = 10 | 學習table | table=10,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 |
UCAST_TO_TUN = 20 | 外出的單播會被 table 20 處理,table 2 |
//學習到的規則 table=20, priority=2,dl_vlan=1,dl_dst=fa:16:3e:7e:ab:cc actions=strip_vlan,set_tunnel:0x3e9,output:5 //如果vlan 為1,而且目的MAC地址等於 fa:16:3e:7e:ab:cc,設置 tunnel id,從端口 5 發出
table=20,priority=0 actions=resubmit(,22) //直接轉 22 |
ARP_RESPONDER = 21 | ARP table | 當使用 arp_responder 和 l2population 時候用到 |
FLOOD_TO_TUN = 22 | Flood table | table=22,dl_vlan=1 actions=strip_vlan,set_tunnel:0x4,output:5,output:4 //對於 dl_vlan 為1的,設置 tunnel id 為 4,從端口4 和 5 轉出 |
來個圖簡單些:
其中比較有意思的是:
(1)為什么從 VXLAN 過來的流量都被丟棄了,最后發出去也用的是 GRE 端口。看來同時有 GRE 和 VXLAN 隧道的話,OVS 只會選擇 GRE。具體原因待查。
(2)MAC 地址學習:Table 10 會將學習到的規則(Local VLAN id + Src MAC Addr => IN_Port)放到 table 20。當表格20 發現一個單播地址是已知的時候,直接從一個特定的 GRE 端口發出;未知的話,視同組播地址從所有 GRE 端口發出。
2.2 MAC 地址學習
學習規則:
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[]
這語法不是很好理解,這里 有詳細解釋。
- table=20:修改 table 20。這是個 MAC 學習流表。
- hard_timeout:該 flow 的過期時間。
-
NXM_OF_VLAN_TCI[0..11] :記錄 vlan tag,所以學習結果中有 dl_vlan=1
-
NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[] :將 mac source address 記錄,所以結果中有 dl_dst=fa:16:3e:7e:ab:cc
-
load:0->NXM_OF_VLAN_TCI[]:在發送出去的時候,vlan tag設為0,所以結果中有 actions=strip_vlan
-
load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[] :發出去的時候,設置 tunnul id,所以結果中有set_tunnel:0x3e9
-
output:NXM_OF_IN_PORT[]:指定發送給哪個port,由於是從 port2 進來的,因而結果中有output:2。
學到的規則:
table=20, n_packets=1239, n_bytes=83620, idle_age=735, hard_age=65534, priority=2,dl_vlan=1,dl_dst=fa:16:3e:7e:ab:cc actions=strip_vlan,set_tunnel:0x3e9,output:2
這里可以看到,通過 MAC 地址學習機制,Neutron 可以一定程度地優化網絡流向,但是這種機制需要等待從別的節點的流量進來,只能算是一種被動的機制,效率不高。而且,這種機制只對單播幀有效,而對於多播和組播依然無效。其結果是網絡成本依然很高。下圖中,A 的廣播包其實只對 3 和 4 有用,但是 2 和 5 也收到了。
3. ARP Responder
arp_responder 的原理不復雜。Neutorn DB 中保存了所有的端口的 MAC 和 IP 地址數據。而 ARP 就是一個虛機要根據另一個虛機的 IP 地址查詢它的 MAC。因此,只需要 Neutron server 通過 RPC 告訴每個計算節點上的 ML2 agent 所有活動端口的 MAC 和 IP,那么就可以將 br-tun 變成一個供本機適用的 ARP Proxy,這樣本機上的虛機的 ARP 請求的響應就可以由 br-tun 在本地解決。Assaf Meller 有篇文章來闡述 ARP Responder。
使用 ARP Responder 需要滿足兩個條件:
(1)設置 arp_responder = true 來使用 OVS 的ARP 處理能力 。這需要 OVS 2.1 (運行 ovs-vswitchd --version 來查看 OVS 版本) 和 ML2 l2population 驅動的支持。當使用隧道方式的時候,OVS 可以處理一個 ARP 請求而不是使用廣播機制。如果 OVS 版本不夠的話,Neutorn 是無法設置 arp responder entry 的,你會在 openvswitch agent 日志中看到 “Stderr: '2015-07-11T04:57:32Z|00001|meta_flow|WARN|destination field arp_op is not writable\novs-ofctl: -:2: actions are invalid with specified match (OFPBAC_BAD_SET_ARGUMENT)\n'”這樣的錯誤,你也就不會在 ”ovs-ofctl dump-flows br-tun“ 命令的輸出中看到相應的 ARP Responder 條目了。
(2)設置 l2_population = true。同時添加 mechanism_drivers = openvswitch,l2population。OVS 需要 Neutron 作為 SDN Controller 向其輸入 ARP Table flows。
3.1 升級 OVS
殺掉 neutron openvswitch, ovs-* 各種進程
#編譯安裝
去 http://openvswitch.org/download/ 下載最新版本的代碼,解壓,進入解壓后的目錄
安裝依賴包,比如 gcc,make
uname -r
./configure --with-linux=/lib/modules/3.13.0-51-generic/build
make && make install
#查看安裝的版本
root@compute2:/home/s1# ovs-vsctl --version
ovs-vsctl (Open vSwitch) 2.3.2
Compiled Jul 12 2015 09:09:42
DB Schema 7.6.2
#處理 db
rm /etc/openvswitch/conf.db (老的db要刪除掉,否則會報錯)
ovsdb-tool create /etc/openvswitch/conf.db vswitchd/vswitch.ovsschema
#啟動 ovs
cp /usr/local/bin/ovs-* /usr/bin
ovsdb-server /etc/openvswitch/conf.db -vconsole:emer -vsyslog:err -vfile:info --remote=punix:/usr/local/var/run/openvswitch/db.sock --private-key=db:Open_vSwitch,SSL,private_key --certificate=db:Open_vSwitch,SSL,certificate --bootstrap-ca-cert=db:Open_vSwitch,SSL,ca_cert --no-chdir --log-file=/var/log/openvswitch/ovsdb-server.log --pidfile=/var/run/openvswitch/ovsdb-server.pid --detach --monitor
ovs-vswitchd unix:/usr/local/var/run/openvswitch/db.sock -vconsole:emer -vsyslog:err -vfile:info --mlockall --no-chdir --log-file=/var/log/openvswitch/ovs-vswitchd.log --pidfile=/var/run/openvswitch/ovs-vswitchd.pid --detach --monitor
#啟動 neutron openvswitch agent,確保log 文件中 ovs-vsctl 和 ovs-ofctl 調用沒有錯誤
#修改 /usr/share/openvswitch/scripts/ovs-lib 文件,保證機器重啟后 OVS 正常運行
將 rundir=${OVS_RUNDIR-'/var/run/openvswitch'} 改為 rundir=${OVS_RUNDIR-'/usr/local/var/run/openvswitch'}
3.2 ARP Responder
有了 arp_responder 以后,br-tun 的流表增加了幾項和處理:
(1)table 2 中增加一條 flow,是的從本地虛機來的 ARP 廣播幀轉到table 21
# ARP broadcast-ed request go to the local ARP_RESPONDER table to be locally resolved
table=2, n_packets=0, n_bytes=0, idle_age=3, priority=1,arp,dl_dst=ff:ff:ff:ff:ff:ff actions=resubmit(,21)
(2)在 table 21 中增加一條 flow 將其發發往 table 22
# If none of the ARP entries correspond to the requested IP, the broadcast-ed packet is resubmitted to the flooding table
table=21, n_packets=0, n_bytes=0, idle_age=4, priority=0 actions=resubmit(,22)
如果下面第 (3)步增加的 flow rule 都處理不了這條 request,那么轉到table 22 去 flood 到所有端口。
(3)由 L2 population 發來的 entry 來更新 table 21。
table 21 是在新的 l2pop 地址進來的時候更新的。比如說,compute C 上增加了新的虛機 VM3,然后計算節點 A 和 B 收到一條 l2pop 消息說 VM3 (IP 是***,MAC 是 ***) 在 Host C 上,在 network "Z“ 中。然后,Compute A 和 B 會在 table 21 中增加相應的 flows。
br.add_flow(table=21, priority=1, proto='arp', dl_vlan=local_vid, nw_dst= ip, actions=actions)
其中action為: (好晦澀,這是誰定義的奇葩語法。。幸好 這里 有詳細解釋)
ARP_RESPONDER_ACTIONS = ('move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],'
'mod_dl_src:%(mac)s,'
'load:0x2->NXM_OF_ARP_OP[],'
'move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[],'
'move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[],'
'load:%(mac)#x->NXM_NX_ARP_SHA[],'
'load:%(ip)#x->NXM_OF_ARP_SPA[],'
'in_port')
(4)table 21 的處理過程
table 21 中的每一條 flow,會和進來的幀的數據做匹配(ARP 協議,network,虛機的 IP)。如果匹配成功,則構造一個 ARP 響應包,其中包括了 IP 和 MAC,從原來的 port 發回到虛機。如果沒有吻合的,那么轉發到 table 22 做泛洪。
增加的 flow tables 在紅色部分:
因此,通過使用 l2-pop mechanism driver 和 OVS 2.1, Neutorn 可以在本地回答虛機的 ARP 請求,從而避免了昂貴的 ARP 廣播。這個功能給 GRE 和 VXLAN 的實現是在 Juno 版本中完成的。 這個 blueprint 似乎在支持VLAN 中的這個功能,但是看起來沒有完成。
4. L2 population
根據這篇文檔,l2pop 目前支持 VXLAN with Linux bridge 和 GRE/VXLAN with OVS,其 blueprint 在這里。
4.1 原理
l2pop 的原理也不復雜。Neutron 中保存每一個端口的狀態,而端口保存了網絡相關的數據。虛機啟動過程中,其端口狀態會從 down 到build 到 active。因此,在每次端口發生狀態變化時,函數 update_port_postcommit 都將會被調用:
{'status': 'DOWN/BUILD/ACTIVE', 'binding:host_id': u'compute1', 'allowed_address_pairs': [], 'extra_dhcp_opts': [], 'device_owner': u'compute:nova', 'binding:profile': {}, 'fixed_ips': [{'subnet_id': u'4ec65731-35a5-4637-a59b-a9f2932099f1', 'ip_address': u'81.1.180.15'}], 'id': u'1167e9ac-e10f-4cf5-bd09-6649eab38b32', 'security_groups': [u'f5377a66-803d-481b-b4c3-a6631e8ab456'], 'device_id': u'30580ea7-c456-416b-a01e-0fe645edf5dc', 'name': u'', 'admin_state_up': True, 'network_id': u'86c0d29b-4880-4739-bd68-eb3c392f5099', 'tenant_id': u'74c8ada23a3449f888d9e19b76d13aab', 'binding:vif_details': {u'port_filter': True, u'ovs_hybrid_plug': True}, 'binding:vnic_type': u'normal', 'binding:vif_type': u'ovs', 'mac_address': u'fa:16:3e:4f:59:9d'}
在某些狀態變化下:
- update_port_postcommit (down to active) -> _update_port_up -> add_fdb_entries -> fdb_add -> fdb_add_tun -> setup_tunnel_port (如果 tunnel port 不存在,則創建 tunnel port), add_fdb_flow -> add FLOOD_TO_TUN flow (如果是 Flood port,則將端口添加到 Flood output ports); setup_entry_for_arp_reply('add'。如果不是 Flood port,那么 添加 ARP Responder entry (MAC -> IP)) 以及 add UCAST_TO_TUN flow Unicast Flow entry (MAC -> Tunnel port number)。
- update_port_postcommit (active to down) -> _update_port_down -> remove_fdb_entries
- delete_port_postcommit (active to down) -> _update_port_down -> remove_fdb_entries -> fdb_remove -> fdb_remove_tun -> cleanup_tunnel_port, del_fdb_flow -> mod/del FLOOD_TO_TUN flow; setup_entry_for_arp_reply ('remove'), delete UCAST_TO_TUN flow
- update_port_postcommit (fixed ip changed) -> _fixed_ips_changed -> update_fdb_entries
通過這種機制,每個節點上的如下數據得到了實時更新,從而避免了不必要的隧道連接和廣播。
- Tunnel port
- FLOOD_TO_TUN (table 22)flow
- ARP responder flow
- UCAST_TO_TUN (table 20) flow
有和沒有 l2pop 的效果:
4.2 過程實驗
1. def tunnel_sync(self) 函數除了上報自己的 local_ip 外不再自己見 tunnels,一切等 l2pop 的通知。
2. 在 compute1 上添加第一個虛機 81.1.180.8
neutron-server:
- 通知 compute1: {'segment_id': 6L, 'ports': {u'10.0.1.21': [['00:00:00:00:00:00', '0.0.0.0'], [u'fa:16:3e:87:40:f3', u'81.1.180.1']]}, 'network_type': u'gre'}}
- 通知所有 agent: {'segment_id': 6L, 'ports': {u'10.0.1.31': [['00:00:00:00:00:00', '0.0.0.0'], [u'fa:16:3e:b3:e7:7a', u'81.1.180.8']]}, 'network_type': u'gre'}}
compute1:
- 添加和網絡節點的tunnel options: {df_default="true", in_key=flow, local_ip="10.0.1.31", out_key=flow, remote_ip="10.0.1.21"}
- 添加到網段網關的 Unicast flow:table=20, n_packets=0, n_bytes=0, idle_age=130, priority=2,dl_vlan=2,dl_dst=fa:16:3e:87:40:f3 actions=strip_vlan,set_tunnel:0x6,output:4
- 增加網段 81.1.180.1 網關的 ARP flows:table=21, n_packets=0, n_bytes=0, idle_age=130, priority=1,arp,dl_vlan=2,arp_tpa=81.1.180.1 actions=move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],mod_dl_src:fa:16:3e:87:40:f3,load:0x2->NXM_OF_ARP_OP[],move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[],move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[],load:0xfa163e8740f3->NXM_NX_ARP_SHA[],load:0x5101b401->NXM_OF_ARP_SPA[],IN_PORT
- 修改 Flood flow
compute 2 節點:因為它上面還沒有運行虛機,所以不做操作。
3. 在 compute 2 上添加一個虛機 81.1.180.9
neutron server:
- 通知 compute 2 : {'segment_id': 6L, 'ports': {u'10.0.1.31': [['00:00:00:00:00:00', '0.0.0.0'], [u'fa:16:3e:b3:e7:7a', u'81.1.180.8']], u'10.0.1.21': [['00:00:00:00:00:00', '0.0.0.0'], [u'fa:16:3e:87:40:f3', u'81.1.180.1']]}, 'network_type': u'gre'}}
- 通知所有 agent: {'segment_id': 6L, 'ports': {u'10.0.1.39': [['00:00:00:00:00:00', '0.0.0.0'], [u'fa:16:3e:73:49:41', u'81.1.180.9']]}, 'network_type': u'gre'}
compute1:
- 建立 tunnel(ID 5): {df_default="true", in_key=flow, local_ip="10.0.1.31", out_key=flow, remote_ip="10.0.1.39"}
- 增加 arp responder flow(compute2 上新的虛機 IP -> MAC):table=21, n_packets=0, n_bytes=0, idle_age=79, priority=1,arp,dl_vlan=2,arp_tpa=81.1.180.9 actions=move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],mod_dl_src:fa:16:3e:73:49:41,load:0x2->NXM_OF_ARP_OP[],move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[],move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[],load:0xfa163e734941->NXM_NX_ARP_SHA[],load:0x5101b409->NXM_OF_ARP_SPA[],IN_PORT
- 增加 unicast flow (新虛機的 MAC -> Tunnel port):table=20, n_packets=0, n_bytes=0, idle_age=79, priority=2,dl_vlan=2,dl_dst=fa:16:3e:73:49:41 actions=strip_vlan,set_tunnel:0x6,output:5
- 添加新的 Tunnel port 到 Flood flow:table=22, n_packets=13, n_bytes=1717, idle_age=255, hard_age=78, dl_vlan=2 actions=strip_vlan,set_tunnel:0x6,output:5,output:4
compute2:
- 建立和計算節點以及compute1的tunnel:options: {df_default="true", in_key=flow, local_ip="10.0.1.39", out_key=flow, remote_ip="10.0.1.21"},options: {df_default="true", in_key=flow, local_ip="10.0.1.39", out_key=flow, remote_ip="10.0.1.31"}
- 增加 ARP flow(compute 1 上的虛機的 MAC -> IP):table=21, n_packets=0, n_bytes=0, idle_age=268, priority=1,arp,dl_vlan=2,arp_tpa=81.1.180.8 actions=move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],mod_dl_src:fa:16:3e:b3:e7:7a,load:0x2->NXM_OF_ARP_OP[],move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[],move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[],load:0xfa163eb3e77a->NXM_NX_ARP_SHA[],load:0x5101b408->NXM_OF_ARP_SPA[],IN_PORT
- 增加 Unicast flow (compute 1 上的虛機 MAC -> Tunnel port):table=20, n_packets=0, n_bytes=0, idle_age=268, priority=2,dl_vlan=2,dl_dst=fa:16:3e:b3:e7:7a actions=strip_vlan,set_tunnel:0x6,output:4
-
增加 ARP flow(新虛機的網關的 MAC -> IP) table=21, n_packets=0, n_bytes=0, idle_age=268, priority=1,arp,dl_vlan=2,arp_tpa=81.1.180.1 actions=move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],mod_dl_src:fa:16:3e:87:40:f3,load:0x2->NXM_OF_ARP_OP[],move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[],move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[],load:0xfa163e8740f3->NXM_NX_ARP_SHA[],load:0x5101b401->NXM_OF_ARP_SPA[],IN_PORT
- 修改 Flood flow(添加到 Compute 1 的 port):table=22, n_packets=13, n_bytes=1717, idle_age=128, dl_vlan=2 actions=strip_vlan,set_tunnel:0x6,output:5,output:4
3. 刪除 compute1 上的一個vm(也是唯一的一個)
neutron server:
- 通知所有 agent: {'segment_id': 6L, 'ports': {u'10.0.1.31': [['00:00:00:00:00:00', '0.0.0.0'], [u'fa:16:3e:b3:e7:7a', u'81.1.180.8']]}, 'network_type': u'gre'}
compute 1:
- 因為沒有別的虛機了,刪除所有 tunnel ports
- 修改或者刪除 ARP, Unicast 和 Flood flows
compute 2:
- 刪除了 compute1 的 tunnel
- 刪除該虛機對應的 ARP flow
4. 在 compute1 上創建第一個不同網絡的虛機
neutron server:
- 通知 compute 1: {u'e2022937-ec2a-467a-8cf1-f642a3f777b6': {'segment_id': 4L, 'ports': {u'10.0.1.21': [['00:00:00:00:00:00', '0.0.0.0'], [u'fa:16:3e:90:e5:50', u'91.1.180.1'], [u'fa:16:3e:17:c9:26', u'90.1.180.1'], [u'fa:16:3e:69:92:30', u'90.1.180.3'], [u'fa:16:3e:69:92:30', u'91.1.180.2']]}, 'network_type': u'gre'}}
- 通知所有 agent:{u'e2022937-ec2a-467a-8cf1-f642a3f777b6': {'segment_id': 4L, 'ports': {u'10.0.1.31': [['00:00:00:00:00:00', '0.0.0.0'], [u'fa:16:3e:e9:ee:0c', u'91.1.180.9']]}, 'network_type': u'gre'}}
compute 1:建立和網絡節點的 tunnel port;更新 Flood flows;添加 ARP flows
compute 2:沒什么action,因為該節點上沒有新建虛機的網絡內的虛機
過程的大概說明:
- 虛機在收到 fannout FDB entries 后,檢查其中每個 port 的 network_id(即 “segment_id”)。如果本機上有該 network 內的 port,那么就處理 entries 中的 “ports”部分;否則,不處理該 entries。
- 因此,當計算節點上沒有運行任何虛機時,不會建立任何 tunnel。如果兩個虛機上有相同網絡內的虛機,那么建立會建立 tunnel。
- 這種機制能實時建立 tunnel port,Flood entry (創建 Tunnel port 同時添加到 Flood output ports 列表), Unicast flow (虛機和網關 MAC -> Tunnel port) 和 ARP Responder entry (虛機和網關 MAC -> IP)。下圖中的藍色部分的流表都會被及時更新。
- Neutron server 在端口創建/刪除/修改時,如果是該節點上的第一個虛機,首先發送直接消息;然后發通知消息給所有的計算和網絡節點。
4.3 性能
4.3.1 MQ 性能問題
應該說 l2pop 的原理和實現都很直接,但是在大規模部署環境中,這種通知機制(通知所有的 ML2 Agent 節點)可能會給 MQ 造成很大的負擔。一旦 MQ 不能及時處理消息,虛機之間的網絡將受到影響。下面是 l2pop 中通知機制代碼:
def __init__(self, topic=topics.AGENT): super(L2populationAgentNotifyAPI, self).__init__( topic=topic, default_version=self.BASE_RPC_API_VERSION) self.topic_l2pop_update = topics.get_topic_name(topic, topics.L2POPULATION, topics.UPDATE) def _notification_fanout(self, context, method, fdb_entries): self.fanout_cast(context, self.make_msg(method, fdb_entries=fdb_entries), topic=self.topic_l2pop_update) def _notification_host(self, context, method, fdb_entries, host): self.cast(context, self.make_msg(method, fdb_entries=fdb_entries), topic='%s.%s' % (self.topic_l2pop_update, host)) def add_fdb_entries(self, context, fdb_entries, host=None): if fdb_entries: if host: self._notification_host(context, 'add_fdb_entries',fdb_entries, host) #cast 給指定 host else: self._notification_fanout(context, 'add_fdb_entries', fdb_entries) #fanout 給所有計算和網絡節點
這段代碼是說,l2pop 采用的 MQ topic 是 “L2POPULATION”,消息通知采用 fanout 或者 cast 機制。如果是 fanout 的話,消息將發到所有的 ML2 agent 節點。這樣的話,其覆蓋面就有些過於廣泛了,就這個問題有人提了一個 ticket,官方答復是 work as design,要改的話只能是添加 new feature 了。
4.3.2 大規模網絡環境中節點上的 OpenFlow flows 過多
不知道這個數目有沒有上限?數目很多的情況下會不會有性能問題?OVS 有沒有處理能力上限?這些問題也許得在實際的生產環境中才能得到證實和答案。
歡迎大家關注我的個人公眾號: