|
|
楼主 |
发表于 2019-10-25 11:23:29
|
显示全部楼层
虽然大部分的OpenStack 部署环境中,都会使用 Open vSwitch 来作为虚拟交换机来实现二层网络功能,但是Neutron 仍然支持使用 Linux bridge 作为虚拟交换机来实现二层网络。本文就此做些分析和说明。 ) z8 l6 F; `& t/ `
同时要指出的是,OpenStack 官方已经把 linux bridge 实现标记为 legacy 的了,文档从 2016 年后也没怎么更新了。这是因为,linux bridge 和 OVS 相比,只支持基本的网络功能即二层交换,但不支持VLAN 标签和隧道。因此,linux bridge agent 利用linux 内核功能(VLAN 子接口和 VXLAN 接口)来实现VLAN 标签和隧道。
2 }) h, t* q. J: G B 6 C! v6 v- p6 o) s- ~8 z* q
1. 测试环境; `2 m8 S( k& N7 H2 f# G
以下面的环境为例(网络节点上):6 ]- R6 S; M- G1 o
(1)linux bridge
- w- H$ L9 M; L* W; K, D# V " k, J2 z) _# k; V& t5 `/ n; F
root@controller:/home/sammy# brctl show: ~* a, R4 c3 z. Y
bridge name bridge id STP enabled interfaces8 S! I' F$ {" c8 N1 p& ~% m
brq85925305-b4 8000.563534c8d02d no tap0bb8efeb-10
3 Y1 h# G; h! K. F7 z# p tap798c87d1-a2
3 {; H' z3 s3 p# P$ e; K# n2 g vxlan-25
7 R- s% k3 p% w9 x2 o; @brq96609bfa-0e 8000.0050569c4d94 no ens224) |& N# h0 @8 G5 [8 `+ f
tap60dbdc2f-a0; C; x0 [7 T" l |. ?
brq971ffda2-e5 8000.a6acb08e4fd6 no tapb1eaae00-e5# b1 M. A+ I6 F
tapf70543dd-0f) t" V6 i# r n( M* F4 y
vxlan-10
$ X+ ]7 L2 J! y. |& a5 ~ [$ H* Y! k4 C
9 R3 `# c" M6 U/ u(2)OpenStack 网络和 network namespace:" ?4 Y$ D6 D( |2 o$ \% f9 c
0 Y2 f A' ^9 Q- T; V$ s6 Troot@controller:/home/sammy# neutron net-list
x2 B; `& `9 J; v% e& |+--------------------------------------+---------+-----------------------------------------------------+: E' }3 K7 D6 b1 [- {+ E; C
| id | name | subnets |$ Y* D3 n0 v* C. O$ U- ^: b; c
+--------------------------------------+---------+-----------------------------------------------------+
, N: M4 K/ ^; P: Z0 D" I| 96609bfa-0e22-4bb7-8dba-6ef532ea6076 | extnet | afa7d205-3026-439f-aca7-295a9f9b2a71 10.62.227.0/24 |
) m+ Z3 j* b7 X| 971ffda2-e567-40a0-a2c8-b31a577fd4d3 | appnet | 4c68eacb-bf3e-408a-a941-94e93eddb22b 11.0.0.0/24 |& t" {; T4 }, J9 R) A3 V/ ]9 K1 i
| | | 3d596991-de8f-4ae4-8913-89426a8abbd7 10.0.0.0/24 |3 l8 A9 k! _! n/ n8 L' K4 F
| 85925305-b477-4cc6-9654-67d9bf1e7cd8 | appnet2 | 4575c7f1-7f08-4917-9904-ec65af38619b 20.0.0.0/24 |2 {! \3 X5 P* h; `
+--------------------------------------+---------+-----------------------------------------------------+$ H' Z. \! z8 {0 |
root@controller:/home/sammy# ip netns; {& ^6 B% c' F1 Q
qdhcp-85925305-b477-4cc6-9654-67d9bf1e7cd8 (id: 2)
/ U+ u* C K/ B1 s' Z$ Uqdhcp-971ffda2-e567-40a0-a2c8-b31a577fd4d3 (id: 1)1 [) d; Q; i: ~
qrouter-39a77439-8a28-49c1-bf97-ac931510631b (id: 0). \3 c4 t9 f1 G4 \ A( X
" j d8 a2 _9 F% F3 m! r6 D
(3)示意图:1 A* `* Q+ r6 s9 A
- R7 W2 ^8 u; E ?
(4)说明: J" p6 ]: c' J& Q
• qdhcp 和 qrouter 都是 linux network namespace 实例; f4 ]' v/ y8 Z7 R ~ N( Y
• qdhcp network namespace 的数量等于启用了 DHCP 的 Neutron network 的数量。
4 a: S7 {' j5 a4 ~8 C6 e! Yo 当一个 network 中存在至少一个 subnet 启用了 DHCP 之后,会有一个 qdhcp network namespace 被创建出来;5 R5 E3 b: _: i- D; l; V- c* _
o 当一个 network 中多个 subnet 启用了 DHCP 时,它们共用一个 qdhcp,以及 dnsmasq。* i+ ]( u5 G& c
o 其 name 使用 network id,比如 qdhcp-85925305-b477-4cc6-9654-67d9bf1e7cd8
2 U% E6 B: m9 M& K4 E8 H1 J( M+ i• qrouter network namespace 的数目等于 router 的数目,也就是说,系统中一共有几个 router,那么就存在几个 qrouter network namespace& d8 H: Z- i- \6 S
• brq linux bridge 的数目等于 neutron network 的数目,其 name 是 network id 的前几位,比如 brq96609bfa-0e. o; `( U5 }$ j% r/ k6 S4 r" N
• 一个 network 的 qdhcp network namespace 和其 brq linux bridge 一定有连接5 j1 {* T5 z) Q0 X5 n2 |
• qrouter 之内的 network interface 分两种,一种是 qr 开头的,每个连接到 router 之上的 subnet 都有一个;还有一个是 qg,每个连接到 router 的 external subnetwork 有一个* x1 V( w% O! [9 e4 j
• qrouter 的每个 network interface 都通过 veth 连接到所在网络的 qbr linux bridge 上# B: u, o" r1 |8 S5 ?
• qbr linux bridge 连连接两种物理设备,一种是 vxlan interface,每个 tenant network 有一个,另一种是在 physical network 对应的物理网卡上创建的子接口(sub-interface)
5 N6 k# p7 N3 X: N• 对于 physical network 的 qbr 来说,用户可以指定它,并且在linuxbridge_agent.ini 中通过 bridge_mappings = List of <physical_network>:<physical_bridge> 进行配置;也可以不指定,此时 agent 会创建它。当同时配置了 physical bridge 和 physical interface 时,前者优先。6 |7 H. r( g" g- d* D
如果 external network 中有多个 subnet 的话:0 E) Q: u* s" x4 G+ i0 }; h( D
(1)每个 qrouter 只允许有一个 External Gateway,也就是说它只有一个 qg network interface。当 external network 添加多个 subnet 之后,只有第一个被当作 external subnet,其余的都会被当作 internal subnet。
4 j7 t8 y8 \! X: `7 i7 r0 q(2)在 qrouter 的路由表之中,' M \+ j$ h2 L8 G
% @) ^/ F$ o. D% r aroot@controller:/home/sammy# ip netns exec qrouter-39a77439-8a28-49c1-bf97-ac931510631b route
; {. s1 e) r! g7 d+ k$ VKernel IP routing table" x4 w$ g) O& d" B6 N$ d
Destination Gateway Genmask Flags Metric Ref Use Iface
" v% _4 e* }9 r. @" }default 10.62.227.1 0.0.0.0 UG 0 0 0 qg-e09fce07-cd! Y' W' R P" _4 }: n
10.0.0.0 * 255.255.255.0 U 0 0 0 qr-b1eaae00-e5
4 d p/ `" ?5 Y" r6 T: R h10.62.227.0 * 255.255.255.0 U 0 0 0 qg-e09fce07-cd
8 T, K, R) @3 t8 U& I' d3 {10.62.228.0 * 255.255.255.0 U 0 0 0 qg-e09fce07-cd
6 a h: K/ R; k5 I3 l10.62.228.0 * 255.255.255.0 U 0 0 0 qr-124ff148-b77 l3 o$ S: g" ~# n, y* ^4 n
11.0.0.0 * 255.255.255.0 U 0 0 0 qr-16d9b0cc-38
; Z- o% O S* r/ [, Z, ^3 A20.0.0.0 * 255.255.255.0 U 0 0 0 qr-0bb8efeb-10# @. G* G0 F) d! w- u# m7 Y
4 B7 Y6 R) i8 H, Y& ?. `
* @( P- E: ?' _: K) B3 U2. linux-bridge-agent 工作过程分析
" B' l% G$ T4 V; u- d5 l2 r8 l(1)linuxbridge-agent 会启动一个循环,不断扫描上面红框中的 tap 设备2 e& R2 T0 I/ Z
) D/ N3 `( _3 A7 S' [) B8 Z2 m) d
def daemon_loop(self):
6 {0 b2 M/ }8 L) E! e/ F6 B2 ~9 M5 V...0 e! F) f& }& F& i- J7 S
while True:3 E9 w4 f& K# \0 j5 \
start = time.time()
% @" h: Y) L8 @# L; [. ..! x( @: A J& w+ Z+ j- Q5 g& y
4 I$ m" g% t& r2 g' h
device_info = self.scan_devices(previous=device_info, sync=sync). I/ h" ^- ~. v4 e' T
sync = False
& ~; O0 y) n) r( P& z4 }! R; T" e+ K+ c3 h6 k" R
if (self._device_info_has_changes(device_info)
6 F2 E; S+ e5 T6 m1 O" N0 @6 V' p or self.sg_agent.firewall_refresh_needed()):. W1 I: p2 d$ {- h
LOG.debug("Agent loop found changes! %s", device_info)
g0 h2 m1 ?7 a' Y% \6 @% A# `. |+ g% A try:
+ C3 s; s3 L8 d$ {$ C0 Q9 k7 n sync = self.process_network_devices(device_info)2 R% D4 g" I( c, H) y H
except Exception:
- F9 E7 o; E# k1 { LOG.exception(_LE("Error in agent loop. Devices info: %s"),
% G9 ^6 ~$ @6 T$ \5 |& X device_info)5 k0 M/ F6 m/ N9 p& U
sync = True
# _9 ^3 @8 T, h; y, _
2 ?: Y9 d* _- _' z& I% N7 m这是它首先找到的 devices:% R" P* V( J* a5 V
(Pdb) p bridge_lib.get_bridge_names() U& _; y2 S. g. a- x3 V) d
['brq85925305-b4', 'virbr0', 'brq971ffda2-e5', 'virbr0-nic', 'tapb1eaae00-e5', 'tapf70543dd-0f', 'vxlan-25', 'vxlan-10', 'tap0bb8efeb-10', 'lo', 'tap60dbdc2f-a0', 'tap795e6e86-94', 'ens224', 'ens192', 'ens160', 'tap798c87d1-a2']
% W/ y0 o$ j( N) i3 `然后过滤出 tap 设备:1 @( u3 E6 n& T% L% N
get_all_devices()->set(['tap0bb8efeb-10', 'tap60dbdc2f-a0', 'tap795e6e86-94', 'tap798c87d1-a2', 'tapb1eaae00-e5', 'tapf70543dd-0f'])
) N) l( {" O, @2 w. d4 K! y(2)根据 previous 中保存的历史数据,再接合服务器端和本地更新时间,计算出需要更新的tap设备列表:" T( l ]5 Q6 u2 z6 o
{'current': set(['tapf70543dd-0f', 'tap60dbdc2f-a0', 'tapb1eaae00-e5', 'tap795e6e86-94', 'tap0bb8efeb-10', 'tap798c87d1-a2']), 'timestamps': {'tapf70543dd-0f': 1476956816.672447, 'tap60dbdc2f-a0': None, 'tapb1eaae00-e5': 1476956816.672447, 'tap795e6e86-94': None, 'tap0bb8efeb-10': 1476689797.1378036, 'tap798c87d1-a2': 1476689701.1349163}, 'removed': set([]), 'added': set(['tapf70543dd-0f', 'tap60dbdc2f-a0', 'tapb1eaae00-e5', 'tap795e6e86-94', 'tap0bb8efeb-10', 'tap798c87d1-a2']), 'updated': set([])} l9 r5 s- `* K" o- ~* |/ B( t8 o
(3) 通过 RPC 获取 tap 设备的详细信息
5 w! X" ]# m9 k( r. m$ P % V; K" [: z9 N9 I1 n) e
(Pdb) p devices) _9 R& i7 F- a% |6 l
set(['tapf70543dd-0f', 'tap60dbdc2f-a0', 'tapb1eaae00-e5', 'tap795e6e86-94', 'tap798c87d1-a2', 'tap0bb8efeb-10'])3 D/ t. Q! @- h' }
- j/ I& p7 m0 t; ?# K. @
: h- R* E/ ~5 s$ y. x4 |" U. Bdevices_details_list = self.plugin_rpc.get_devices_details_list
* V+ x; ?; R* P8 l. Y. A6 O M; _
. O1 y7 G. C" ~$ S* w) N(Pdb) p devices_details_list/ [3 x% V5 J9 b1 I& ^
[{u'profile': {}, u'network_qos_policy_id': None, u'qos_policy_id': None, u'allowed_address_pairs': [], u'admin_state_up': True, u'network_id': u'971ffda2-e567-40a0-a2c8-b31a577fd4d3', u'segmentation_id': 10, u'device_owner': u'network:dhcp', u'physical_network': None, u'mac_address': u'fa:16:3e:5c:bf:11', u'device': u'tapf70543dd-0f', u'port_security_enabled': False, u'port_id': u'f70543dd-0f1b-4e1d-93c7-33f4f3d7a709', u'fixed_ips': [{u'subnet_id': u'3d596991-de8f-4ae4-8913-89426a8abbd7', u'ip_address': u'10.0.0.10'}], u'network_type': u'vxlan', u'security_groups': []}, {u'profile': {}, u'network_qos_policy_id': None, u'qos_policy_id': None, u'allowed_address_pairs': [], u'admin_state_up': True, u'network_id': u'96609bfa-0e22-4bb7-8dba-6ef532ea6076', u'segmentation_id': None, u'device_owner': u'network:router_gateway', u'physical_network': u'provider', u'mac_address': u'fa:16:3e:77:78:86', u'device': u'tap60dbdc2f-a0', u'port_security_enabled': False, u'port_id': u'60dbdc2f-a01b-446d-bb5b-26ffac19a045', u'fixed_ips': [{u'subnet_id': u'afa7d205-3026-439f-aca7-295a9f9b2a71', u'ip_address': u'10.62.227.151'}], u'network_type': u'flat', u'security_groups': []}, {u'profile': {}, u'network_qos_policy_id': None, u'qos_policy_id': None, u'allowed_address_pairs': [], u'admin_state_up': True, u'network_id': u'971ffda2-e567-40a0-a2c8-b31a577fd4d3', u'segmentation_id': 10, u'device_owner': u'network:router_interface', u'physical_network': None, u'mac_address': u'fa:16:3e:81:1b:37', u'device': u'tapb1eaae00-e5', u'port_security_enabled': False, u'port_id': u'b1eaae00-e504-41f8-93a4-643687155bea', u'fixed_ips': [{u'subnet_id': u'3d596991-de8f-4ae4-8913-89426a8abbd7', u'ip_address': u'10.0.0.1'}], u'network_type': u'vxlan', u'security_groups': []}, {u'profile': {}, u'network_qos_policy_id': None, u'qos_policy_id': None, u'allowed_address_pairs': [], u'admin_state_up': True, u'network_id': u'96609bfa-0e22-4bb7-8dba-6ef532ea6076', u'segmentation_id': None, u'device_owner': u'network:dhcp', u'physical_network': u'provider', u'mac_address': u'fa:16:3e:5f:94:7d', u'device': u'tap795e6e86-94', u'port_security_enabled': False, u'port_id': u'795e6e86-94af-4b72-ae1a-5a324a017774', u'fixed_ips': [{u'subnet_id': u'afa7d205-3026-439f-aca7-295a9f9b2a71', u'ip_address': u'10.62.227.150'}], u'network_type': u'flat', u'security_groups': []}, {u'profile': {}, u'network_qos_policy_id': None, u'qos_policy_id': None, u'allowed_address_pairs': [], u'admin_state_up': True, u'network_id': u'85925305-b477-4cc6-9654-67d9bf1e7cd8', u'segmentation_id': 25, u'device_owner': u'network:dhcp', u'physical_network': None, u'mac_address': u'fa:16:3e:25:27:99', u'device': u'tap798c87d1-a2', u'port_security_enabled': False, u'port_id': u'798c87d1-a2d8-4df7-b7fc-5ab30918a0de', u'fixed_ips': [{u'subnet_id': u'4575c7f1-7f08-4917-9904-ec65af38619b', u'ip_address': u'20.0.0.100'}], u'network_type': u'vxlan', u'security_groups': []}, {u'profile': {}, u'network_qos_policy_id': None, u'qos_policy_id': None, u'allowed_address_pairs': [], u'admin_state_up': True, u'network_id': u'85925305-b477-4cc6-9654-67d9bf1e7cd8', u'segmentation_id': 25, u'device_owner': u'network:router_interface', u'physical_network': None, u'mac_address': u'fa:16:3e:9f:18:a9', u'device': u'tap0bb8efeb-10', u'port_security_enabled': False, u'port_id': u'0bb8efeb-108f-409a-82e7-c4c20f0d4f69', u'fixed_ips': [{u'subnet_id': u'4575c7f1-7f08-4917-9904-ec65af38619b', u'ip_address': u'20.0.0.1'}], u'network_type': u'vxlan', u'security_groups': []}]
: Z5 D) u; k% Q6 }9 u& z
6 ~7 j: c. o3 I& l(4) 对需要处理的设备,调用 self.process_network_devices(device_info) 函数进行处理
1 v1 n2 i( @" h" f5 S$ R# b(5). 调用 plug_interface( [/ O" ? X& o& f4 m
interface_plugged = self.mgr.plug_interface(network_id, segment,device, device_details['device_owner'])! {! h& L' n7 I( Q
(6). 需要的话,使用已经配置的或者新建 linux brige,并将 physical interface 设备加入其中
! |. H/ Q8 [, U% O; `( Obridge_name = self.get_existing_bridge_name(physical_network) #获取为 physical network 配置的 linux bridge1 G! k' Y6 S$ a1 c3 i+ M1 K0 R
bridge_name = self.get_bridge_name(network_id) #或者根据 network id 生成 bridge name( R# u% X7 T8 i( X" M8 G
(7).根据不同的网络类型,分别处理 vxlan bridge,flat bridge 和 vlan bridge \7 a& w5 ]) `$ G% v9 @4 ^$ v
+ ]8 Z' A! V3 k* b def ensure_physical_in_bridge(self, network_id,
5 J1 v' R" E( E network_type,7 V) G+ r! O* G: H6 U
physical_network,, ^% _, r' J8 ?5 H
segmentation_id):" I( Y+ i% j9 B5 s7 r# D, o% n
if network_type == p_const.TYPE_VXLAN:
6 s3 I8 @+ q# D6 s if self.vxlan_mode == lconst.VXLAN_NONE:+ ?2 B- W# k+ p- }
LOG.error(_LE("Unable to add vxlan interface for network %s"),
: V2 c# Q% V* g: d5 h% | p network_id)% V4 J+ Q9 N/ r
return3 B( i5 ]7 I8 e! B5 t, J: s/ m& H
return self.ensure_vxlan_bridge(network_id, segmentation_id)
?: J7 N6 | U) q/ b- P" l5 Z* r4 h. L8 V( I6 \) D" G9 f# _
# NOTE(nick-ma-z): Obtain mappings of physical bridge and interfaces
" p2 g$ }" B& S( U physical_bridge = self.get_existing_bridge_name(physical_network)
: X! W- Z8 f6 k5 o6 G7 C$ k" w physical_interface = self.interface_mappings.get(physical_network)
& k6 R# T/ N0 M) z if not physical_bridge and not physical_interface:0 ^6 V9 v9 n* \$ y* d
LOG.error(_LE("No bridge or interface mappings"7 o' t4 V* E6 a
" for physical network %s"),, H& ^" A8 }. F: j' Q- p ~( N
physical_network)* z7 O* L8 A8 Z
return9 K( |* z$ ?/ j
if network_type == p_const.TYPE_FLAT:$ J! n1 N7 v; w7 b6 p
return self.ensure_flat_bridge(network_id, physical_bridge,
! C8 n( v2 I4 ?7 b# u* C: O physical_interface). K" H/ c" C5 @% u7 I$ U
elif network_type == p_const.TYPE_VLAN:! ~# u9 m# d! F5 r% t. N
return self.ensure_vlan_bridge(network_id, physical_bridge,8 \/ t/ x" [# ^8 Y
physical_interface,
* O$ ?7 S- }8 o G" q segmentation_id)
" \, }, @9 K9 T+ T" f2 O
9 e. `1 S* R) h# z& s7 {5 ?& Z* F( x对于 flat 类型的网络,调用 ensure_physical_in_bridge' z4 z7 ^. ?2 G, b# h
def ensure_physical_in_bridge(self, network_id,network_type,physical_network,segmentation_id)" c7 c/ S& E' r- O/ O/ r5 E
if network_type == p_const.TYPE_FLAT:
; |7 m/ {2 O, Y) L0 R; g* x return self.ensure_flat_bridge(network_id, physical_bridge,physical_interface)7 V. O1 J+ M( o. Y9 Z! A
如果有配置 physical bridge 的话,使用它;否则创建 bridge,并将物理网卡配置的 ip 地址和 gateway 从网卡挪到 linux bridge) y- H! o$ U `. @; ?9 c
9 a& [- h' A+ m! m6 @. @
def ensure_flat_bridge(self, network_id, phy_bridge_name,physical_interface):
; D6 z, g* X: t& L) v """Create a non-vlan bridge unless it already exists."""% I0 O5 P: [4 O* B" {4 s! F
if phy_bridge_name:! l l6 t) |0 \8 ~
return self.ensure_bridge(phy_bridge_name) #获取预先配置好的 linux bridge
9 @, g% E4 f' `. C$ T% { else:1 o' U6 E- [6 N5 \7 y& j( i$ e
bridge_name = self.get_bridge_name(network_id)* y6 E9 w1 P7 ]) I$ b
ips, gateway = self.get_interface_details(physical_interface)
' X% B( c9 I; J" D2 z& q: o if self.ensure_bridge(bridge_name, physical_interface, ips,gateway): #创建 bridge
* \' q" P5 \! y! b return physical_interface ^, p' Q+ ]! U/ ~, i, G2 N& Y7 Q2 C& r
& T8 P3 Z5 y9 d+ m9 t5 q+ K
对于 vxlan 类型的 network,需要创建 vxlan interface
' b- i. o' U* T6 T. B3 R7 z 5 z( {1 y! c% T8 R* Q( s) |
def ensure_vxlan_bridge(self, network_id, segmentation_id):4 \% m" D% T( E4 B, q4 Q% c
"""Create a vxlan and bridge unless they already exist."""; J2 E5 w2 X9 i' w7 D' p
interface = self.ensure_vxlan(segmentation_id)
4 H/ F5 e% u, }/ D5 p if not interface:( Q3 \5 g! x0 w7 e! @# d( e* c+ G
LOG.error(_LE("Failed creating vxlan interface for "
9 h% B+ u% N G$ b9 K% h, c, y "%(segmentation_id)s"),
$ C% g8 x1 J' Y u {segmentation_id: segmentation_id})* l6 K4 F1 _9 B, h: ?( I
return% g) A! y+ N! d7 r4 @. D% ?4 a- F
bridge_name = self.get_bridge_name(network_id)
" S% {6 E% ?1 }/ q0 m: Q4 `. e* E self.ensure_bridge(bridge_name, interface)
8 q' w" q! t3 F* J return interface6 ^3 ]" O7 L. g3 A; h7 K) G
) d8 K g( p) ?# x: a- U( G0 u创建 vxlan interface:
/ ~" r. u* h9 c; g ! z- M/ {: [. S% ^" D
def ensure_vxlan(self, segmentation_id):
; C) m, ?" K- C% A """Create a vxlan unless it already exists."""
; v W& ]4 b7 l* Y2 W interface = self.get_vxlan_device_name(segmentation_id)3 ]# f$ J# r; R' a, M7 `9 B) N1 V
if not ip_lib.device_exists(interface):8 n6 g' n6 T) A/ q" }
LOG.debug("Creating vxlan interface %(interface)s for "/ B# y$ l/ c% K
"VNI %(segmentation_id)s",
7 d0 M5 K, s T/ Y {'interface': interface,
9 x8 `) E) m& N# D 'segmentation_id': segmentation_id})
. {0 x- S3 {" ?% N args = {'dev': self.local_int}
+ Z, R5 a9 I! M1 g/ r; O if self.vxlan_mode == lconst.VXLAN_MCAST:
4 }* q1 Z- Z4 H( a+ b3 M- G args['group'] = self.get_vxlan_group(segmentation_id)
, T5 C; i' r! H/ a$ `) i" r8 U$ @ if cfg.CONF.VXLAN.ttl:( o$ w9 i. H9 Q! X/ W
args['ttl'] = cfg.CONF.VXLAN.ttl
4 ]# B( |/ }6 m if cfg.CONF.VXLAN.tos:
. e& U4 s3 T$ }4 F N/ ? args['tos'] = cfg.CONF.VXLAN.tos
3 P* C" ~( W% J q* [1 K if cfg.CONF.VXLAN.l2_population:
0 |5 H. u! I4 U* w2 j3 N args['proxy'] = cfg.CONF.VXLAN.arp_responder
* ~6 p( O/ M# X4 W; C5 {; E try:
5 ^$ H4 x- {7 N: y, L int_vxlan = self.ip.add_vxlan(interface, segmentation_id,
! q7 ^9 b% S4 [: m **args)' v7 {8 Z7 J% D* W1 I0 Y# t, D
8 i5 v" `; q A% b; ?% {* P/ I
(8). 将 tap 设备加入到 linux bridge 中' O5 K5 {# c& ^/ j5 |+ V4 Y" Z4 l
bridge_lib.BridgeDevice(bridge_name).addif(tap_device_name)
6 r7 `; s3 P' N5 j7 ~7 S5 L(9). 如果将一个 tap 设备被删除,那么 linux-bridge-agent 会发现:
! ^% ?! ^+ I! ^. R/ x9 f2016-10-26 10:29:58.347 30219 INFO neutron.agent.securitygroups_rpc [req-e3264065-6414-4b5a-8d2b-dfafad6fdde8 - - - - -] Remove device filter for set(['tap60dbdc2f-a0'])
+ [7 [1 M, w% |5 H" S' B- W2016-10-26 10:29:58.433 30219 INFO neutron.plugins.ml2.drivers.agent._common_agent [req-e3264065-6414-4b5a-8d2b-dfafad6fdde8 - - - - -] Attachment tap60dbdc2f-a0 removed
/ p! Y, ^. K2 P! @2016-10-26 10:29:58.536 30219 INFO neutron.plugins.ml2.drivers.agent._common_agent [req-e3264065-6414-4b5a-8d2b-dfafad6fdde8 - - - - -] Port tap60dbdc2f-a0 updated.
% s5 I2 f8 g2 e: |2 `3. 关于上述工作过程的简单结论 L6 V/ X ?( v4 M3 p
3.1 简单结论
: }/ c: A4 U$ S1. l3agent 和 dhcpagent 创建 network namespace 时创建 tap 设备,和 network namespace 中的 interface 是一对 veth pair。当手工删除 tap 设备时,相应的 veth endpoint 也会被删除。4 j! _- g3 G4 G, N# x& A, e8 T" C
2. linuxbridgeagent 不断扫描服务器端和本地的 tap 设备& y! u! u9 K6 q# H* o3 ^
3. linuxbridgeagent 获取需要增加和修改的tap设备列表
5 f# c$ Q1 \) b& p3 R5 w4. 对于需要增加的 tap 设备,获取其详细信息,主要是 network_id,network_type,physical_network,segmentation_id,device_owner 等,然后根据这些信息,创建 linux bridge,并加入所需要的 interface2 ^3 ?. c- O5 Z) N a
5. 创建所需要的 linux bridge,并将 physical interface (provider network 的 physical interface 或者 tenant network 的 vxlan interface)加入 bridge,并且将 tap 设备也加入该 bridge# o }) Q% b9 A5 X+ B
6. 如果发现某个 linux bridge 没有创建出来,首先需要查看有没有相应的 tap 设备存在;如果 tap 设备不存在,则查看相应的 qdhcp 或者 qrouter 中时候有interface
6 S3 [0 i6 J# x+ c8 D+ t " d2 _; [$ v7 B- D5 N
具有多个 VLAN 租户网络时候的网络元素示意图:
9 @1 ~2 s& k `' z' S8 v
9 }( Z6 k. k3 o1 o0 v9 r
6 u# d+ P# I! _
; X8 ^! U$ |+ b2 x y/ X5 D6 R 3 L: g% R" T' J5 D
3.2 关于 unnumber interface* V6 X, r x0 T( z' Q W, m
OpenStack 官方的 host networking 配置中,连接外网的 interface 可以是 unnumbered 的,从字面意思理解,就是该 interface 上不需要配置 IP 地址。
' k: ?! U( E# _ ' U% a) U, A$ }2 D
配置的时候,修改 /etc/network/interfaces:
; q; B: T4 Q% | e' B# The provider network interface
4 z3 u6 Q/ i5 A5 M6 b9 g! rauto ens224
& a/ Z2 D/ ?$ U3 m* K) qiface ens224 inet manual
7 \! Z9 \! n- q" R( Q' u0 _- m4 aup ip link set dev $IFACE up0 C$ c: K. X! w! x/ W, F5 a
down ip link set dev $IFACE down
- Y, R0 o1 ~+ \' \8 C配置好以后:
( @1 S( K3 x% @# u & S @( u$ ~1 \, @5 ^" f& N
root@controller:/home/sammy# ifconfig ens224
8 g3 W" l/ A" ~' }ens224 Link encap:Ethernet HWaddr 00:50:56:9c:4d:94
. _+ {/ ^0 D/ ?1 V) c UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
* V/ V) g' T0 {- v( m- {( g- z RX packets:27300737 errors:0 dropped:0 overruns:0 frame:0
4 y2 y9 f6 }& U( p: s TX packets:61547 errors:0 dropped:0 overruns:0 carrier:0
5 g0 r: S: T4 n1 V9 b! h- p4 F collisions:0 txqueuelen:1000
8 X: q& |7 C. [5 L8 v9 c/ F- m RX bytes:31951077598 (31.9 GB) TX bytes:5966060 (5.9 MB)
2 K2 e$ h, n1 w* T( E
* J! h# V+ C# N" q4 y0 P* f6 |root@controller:/home/sammy# ifconfig brq96609bfa-0e
* X9 e/ E I; t- C( s4 z2 ibrq96609bfa-0e Link encap:Ethernet HWaddr 00:50:56:9c:4d:94
. t' {9 C0 T/ a6 J) D3 X% }( M UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1: Y2 T, y F7 O- ]- e# X
RX packets:32855 errors:0 dropped:0 overruns:0 frame:0# ~5 w, g# `% x' e( a S6 c
TX packets:2 errors:0 dropped:0 overruns:0 carrier:0
2 B; K7 U, A1 k8 a, z3 P5 W% o; k7 d) w collisions:0 txqueuelen:1000
+ I3 B! A. S w0 w1 P- x RX bytes:2731030 (2.7 MB) TX bytes:84 (84.0 B)
/ Q r4 I: s" Z4 x ; \& M& ~) U0 i) W
具体原理不详,但是应该是因为 qrouter 的 qg network interface 和物理网络中的路由器的网卡之间是网络二层,因此中间的设备都是属于二层的,因此不需要处于网络三层的 IP 地址。0 J- n2 B& N# S9 C: d; T f" K" Y
4. 使用 linux bridge 时的拓扑结构$ ^1 o( X% _5 H, S/ m* u+ u" U
4.1 网络节点上
- }3 [9 ^9 W% k4 H1 v为了更清楚,我们来对比着看 linux bridge 和 ovs 的两种方案:
, z x8 H1 p# Plinux 方案:
. p6 A. N/ L1 a! \! D+ q" x 4 y4 ^8 q% R- K* N' s
网络服务:/ w( ^7 r$ U5 Z' c6 Q
• Linux bridge agent' K, r. X) J, T( A: k# @$ f8 E9 C
• L3 agent
3 }# j7 E$ d# ]. s) ?. G• DHCP agent9 P' f( K3 v) d6 G
• Metadata agent# s( m6 \4 M4 k
Linux bridge agent 会为每个 VLAN 虚拟网络创建一个 VLAN Bridge,它连接多个网元:
- c2 a# U* t+ r: |• VLAN 子接口,从物理网卡(图中的 interface3)上创建,每个子接口对应一个VLAN ID,其名称格式为 device.sid,其中 device 是物理网卡名字比如 eth0,sid 是 vlan id。, O$ d5 l% n2 _4 r
• 连接虚拟机的 tap 接口0 Q k( K8 x' t8 r* Y8 F; h6 H
• 和 qrouter 连接的 tap 接口
& Q8 ^5 [* o8 W6 \2 l4 Y• 和该网络的 qdhcp 连接的 tap 接口
. c* W+ }3 h, Y1 b) N5 |如果同时有 VXLAN 虚拟网络的话(linux-bridge 不支持GRE 隧道模式),会为每个 VLAN 虚拟网络创建一个 Tunnel bridge。它连接多个网元:6 Z( n7 M! S+ y0 D1 ^* ~' U0 Q
• vxlan interface,这种接口每个虚拟网络一个,名字格式为 vxlan-sid,其中 sid 是分段ID。
! B! C/ ?. b9 M$ C- ~• 连接虚拟机的 tap 接口
1 H) t0 x1 ]2 A• 和 qrouter 连接的 tap 接口( Y4 P7 w3 y8 t5 S8 w$ U$ S
• 和该网络的 qdhcp 连接的 tap 接口
1 q% P5 X4 v6 F& l安全组规则在 tunnel bridge 和 vlan bridge 上。6 S; O( i& z& ^ H3 t/ Z- {
OVS 方案:
8 d# K9 z& K1 E' u
8 C, Y/ E" V- v/ I& @* C这里面,br-int 会负责加本地 VLAN 标签,br-tun 会负责将 VLAN ID 转换为 VXLAN ID。9 u0 N+ R+ S/ K. N2 G1 u
6 o( V0 q' J* f4 D B3 C1 d$ n1 {6 Z4.2 计算节点上
+ x, n1 Z% o, _7 Q2 `同样来对比着看。( A, u& m, C% X4 g* A
linux bridge:$ f; e d2 S+ l% C7 V+ \
5 @2 M8 L. E% J* Y9 X
网络服务:( H2 F$ Z& H# t" }; n
• Linux bridge agent
1 `% X1 Q' E; M5 x! o; {( @和网络节点类似,只不过没有 qrouter 和 qdhcp,不在赘述。8 S$ {& Y% @# r" E
OVS:
9 y+ A9 \; o, A ]" x: f2 }- w + J$ z& F" P- p2 j' ?
6 l6 b7 F- G8 R
OVS 放在在 br-int 上实现 VLAN 标签,在 br-tun 上实现隧道,在 qbr linux bridge 上实现安全组。
6 l, Z" n, Z/ N9 `& `- o+ `" a2 T
9 c/ N$ ` f0 a3 M; i/ x5 F4.3 网络路径 - 南北向网络流向
; Q! i5 j- a$ R3 `0 X* a! F# G & Y1 S1 w' E7 E e
VLAN 网络和VXLAN 网络井水不犯河水。这图上的配置中,计算节点和网络节点上的物理网卡都分开了。
" g8 I. R7 e5 @2 ~/ b( f4.4 网络路径 - 东西向(不同网络)/ V, d( N. J) m6 G! Z9 |! v
- b: k# f1 v; p' d! H Y
4.5 网络路径 - 东西向(同一个网络)
& s" |7 B9 ~, V* n ^
8 Z/ t9 N8 p/ C( P |
5 |! o/ I% U9 u8 F8 W请详细说明和配置,请参阅参考文档。3 O8 g7 f- p z5 {, {6 X/ b
5. 一点结论5 g1 g4 P! K% Q% X
和基于 OVS 的二层网络相比,
" j T l& A2 X8 R( ~' v5 J; Q, R# N• 功能和架构上:基于 linux bridge 的实现还是有一些短处,比如每个虚拟网络就需要一个网桥,这在大规模环境中会带领资源使用和管理上的问题。其好处是本身架构比较清晰。
& G/ [# M7 p$ Q4 q• 性能上:基本上差不多,如下图所示,不管是 vxlan 还是 vlan。* `; a& X3 W( p2 t/ L8 a
* O) @7 d6 t: V; x
; \6 m8 }8 a" Z9 `& O/ F4 Z! f) y- J
|
|