- 积分
- 16843
在线时间 小时
最后登录1970-1-1
|

楼主 |
发表于 2019-10-25 11:23:29
|
显示全部楼层
虽然大部分的OpenStack 部署环境中,都会使用 Open vSwitch 来作为虚拟交换机来实现二层网络功能,但是Neutron 仍然支持使用 Linux bridge 作为虚拟交换机来实现二层网络。本文就此做些分析和说明。 6 C# ?: B( H2 n. P
同时要指出的是,OpenStack 官方已经把 linux bridge 实现标记为 legacy 的了,文档从 2016 年后也没怎么更新了。这是因为,linux bridge 和 OVS 相比,只支持基本的网络功能即二层交换,但不支持VLAN 标签和隧道。因此,linux bridge agent 利用linux 内核功能(VLAN 子接口和 VXLAN 接口)来实现VLAN 标签和隧道。! S+ k! O; W5 o
( P9 V' B# K8 \: f
1. 测试环境
1 u# K3 i* N% I" v {2 R, y* |; [以下面的环境为例(网络节点上):+ Q* H: H' S9 N p1 u4 P6 ], c
(1)linux bridge! Y; w5 K0 S6 w) V8 y8 q$ J' G
$ D( Z. }/ A( Q" E2 t4 ]2 w6 R4 Lroot@controller:/home/sammy# brctl show
2 j: \' ]3 I) x5 Y0 H xbridge name bridge id STP enabled interfaces
8 y' ^" |: Y: L5 ]brq85925305-b4 8000.563534c8d02d no tap0bb8efeb-102 n2 q. ~! h8 X+ t) H6 b6 f
tap798c87d1-a2' z, M3 O) _5 p& H1 `6 i' l2 w
vxlan-25
) J6 e/ t5 G8 b& }5 D& g* zbrq96609bfa-0e 8000.0050569c4d94 no ens224
; ]) P7 a+ \8 ?7 E% P tap60dbdc2f-a0
: B# f& C) x; D& G: }brq971ffda2-e5 8000.a6acb08e4fd6 no tapb1eaae00-e58 a( j, ]8 A. a+ M9 h" K9 m
tapf70543dd-0f6 {$ u2 ^, e1 x2 a% Q2 y5 k: H
vxlan-10
5 G& I% O. Q! V6 p, {
8 X( |3 w1 X8 X& E: T6 J(2)OpenStack 网络和 network namespace:
$ v! s5 |/ Y5 L
/ L6 s: G$ j5 w' j) y- c" ]7 aroot@controller:/home/sammy# neutron net-list H- ]2 g% @ I/ U* z
+--------------------------------------+---------+-----------------------------------------------------+
$ `8 h$ W8 X, R5 c3 v4 `5 d| id | name | subnets |! H8 {: z& l* s- [# O& d5 V
+--------------------------------------+---------+-----------------------------------------------------+
2 W0 ~8 \6 X! r# {! @6 j| 96609bfa-0e22-4bb7-8dba-6ef532ea6076 | extnet | afa7d205-3026-439f-aca7-295a9f9b2a71 10.62.227.0/24 |
& \% x/ f' \ L, A| 971ffda2-e567-40a0-a2c8-b31a577fd4d3 | appnet | 4c68eacb-bf3e-408a-a941-94e93eddb22b 11.0.0.0/24 |) W& b3 T" Q$ a. Q" ^
| | | 3d596991-de8f-4ae4-8913-89426a8abbd7 10.0.0.0/24 |
X, f) S% } n% d. K& L| 85925305-b477-4cc6-9654-67d9bf1e7cd8 | appnet2 | 4575c7f1-7f08-4917-9904-ec65af38619b 20.0.0.0/24 |
2 N" J& H7 S' |$ L+--------------------------------------+---------+-----------------------------------------------------+' p6 ?1 m0 o6 H/ R3 _. f
root@controller:/home/sammy# ip netns
% Q n6 H7 l$ S% R% ?" m: N$ i% Zqdhcp-85925305-b477-4cc6-9654-67d9bf1e7cd8 (id: 2)
. W7 T3 ]+ Q" @1 `8 fqdhcp-971ffda2-e567-40a0-a2c8-b31a577fd4d3 (id: 1)
. ^8 }. ~' ^# }qrouter-39a77439-8a28-49c1-bf97-ac931510631b (id: 0)9 M8 P( |4 W) F( N+ ?. h/ D
3 Y$ M& ^7 p! }# R# B
(3)示意图:9 v; L( B# ?- _: t: H+ `8 x1 S
- f7 T0 ~ \! j& G(4)说明:0 C. D) Y% v1 B8 Z, w3 Z
• qdhcp 和 qrouter 都是 linux network namespace 实例+ @& C$ A3 E5 K
• qdhcp network namespace 的数量等于启用了 DHCP 的 Neutron network 的数量。! T, o* \8 W8 q O5 F# T
o 当一个 network 中存在至少一个 subnet 启用了 DHCP 之后,会有一个 qdhcp network namespace 被创建出来;) A6 i8 S' m1 D1 ]9 _# s. C
o 当一个 network 中多个 subnet 启用了 DHCP 时,它们共用一个 qdhcp,以及 dnsmasq。7 ~+ ^6 a) X5 ]
o 其 name 使用 network id,比如 qdhcp-85925305-b477-4cc6-9654-67d9bf1e7cd8. f- n; [5 M" J1 g3 Q# Z7 w
• qrouter network namespace 的数目等于 router 的数目,也就是说,系统中一共有几个 router,那么就存在几个 qrouter network namespace
; R6 [: a" `/ y- Q) r3 K• brq linux bridge 的数目等于 neutron network 的数目,其 name 是 network id 的前几位,比如 brq96609bfa-0e
8 E& x, v; P% H; b+ M. e. r• 一个 network 的 qdhcp network namespace 和其 brq linux bridge 一定有连接' R6 {, ^; n1 K. x
• qrouter 之内的 network interface 分两种,一种是 qr 开头的,每个连接到 router 之上的 subnet 都有一个;还有一个是 qg,每个连接到 router 的 external subnetwork 有一个: Y- N8 k9 _; H/ X! P/ g5 p
• qrouter 的每个 network interface 都通过 veth 连接到所在网络的 qbr linux bridge 上
/ n# l% |5 g2 R, `8 U• qbr linux bridge 连连接两种物理设备,一种是 vxlan interface,每个 tenant network 有一个,另一种是在 physical network 对应的物理网卡上创建的子接口(sub-interface)
' F- n5 K2 n! E. h, v6 `, j( O) [• 对于 physical network 的 qbr 来说,用户可以指定它,并且在linuxbridge_agent.ini 中通过 bridge_mappings = List of <physical_network>:<physical_bridge> 进行配置;也可以不指定,此时 agent 会创建它。当同时配置了 physical bridge 和 physical interface 时,前者优先。
: k; g- Q( i9 Q: A/ k* ]7 F+ U如果 external network 中有多个 subnet 的话:
6 e* m8 ~6 M& Q0 S2 C* I2 K% g3 W(1)每个 qrouter 只允许有一个 External Gateway,也就是说它只有一个 qg network interface。当 external network 添加多个 subnet 之后,只有第一个被当作 external subnet,其余的都会被当作 internal subnet。' z* i+ [1 ?# N0 E! E/ x( C9 L
(2)在 qrouter 的路由表之中,
) ]+ C; }; F8 J8 m1 O5 w) e
7 [$ X) V+ y0 B& {( L2 d% groot@controller:/home/sammy# ip netns exec qrouter-39a77439-8a28-49c1-bf97-ac931510631b route" k8 z2 Q! E3 J8 b3 L) L
Kernel IP routing table& a8 J4 }( c, c* J/ j- p6 P
Destination Gateway Genmask Flags Metric Ref Use Iface$ J" ~# {! b% k0 i; {# n
default 10.62.227.1 0.0.0.0 UG 0 0 0 qg-e09fce07-cd* f& E( _' [- k' Y
10.0.0.0 * 255.255.255.0 U 0 0 0 qr-b1eaae00-e53 `2 E _- X! s% i! p: ?
10.62.227.0 * 255.255.255.0 U 0 0 0 qg-e09fce07-cd
; N- o; }+ Q7 m! u4 L6 M Q10.62.228.0 * 255.255.255.0 U 0 0 0 qg-e09fce07-cd
7 E1 W$ S+ ~: g n3 @10.62.228.0 * 255.255.255.0 U 0 0 0 qr-124ff148-b7
' L+ v. W$ h, P4 W11.0.0.0 * 255.255.255.0 U 0 0 0 qr-16d9b0cc-382 n" w' A5 ^, h+ c
20.0.0.0 * 255.255.255.0 U 0 0 0 qr-0bb8efeb-10, q4 K; i* x* k8 r
. {" G* V' M- m P0 E/ W4 V M' ~
2. linux-bridge-agent 工作过程分析
% a' b; p9 m* @* e' V- S(1)linuxbridge-agent 会启动一个循环,不断扫描上面红框中的 tap 设备7 `3 s7 c+ N8 @6 H: ]
5 j8 X- G2 f9 r* l6 w
def daemon_loop(self):3 E2 q4 S& G6 W. \( A E n: R
...
: @0 {" F1 s. g) c- D. C while True:1 r- u9 Z! M- u
start = time.time()
: D: G! R9 s8 x7 g* s& U! N% L% S. ..
7 n/ G% l# t, x: t7 G: G* M7 c- j( I! W4 Y/ K" h
device_info = self.scan_devices(previous=device_info, sync=sync)
4 Y& |; r c( v6 ?9 p4 u sync = False+ E6 ]& Q, A8 Z3 K
9 K& i0 o. Y0 |4 a2 N, x if (self._device_info_has_changes(device_info)$ M% Q/ I' V$ A
or self.sg_agent.firewall_refresh_needed()):9 W' H$ u# H% @0 b! S
LOG.debug("Agent loop found changes! %s", device_info)
) i8 L U9 [; y- ^( [- v try:4 `+ }+ a; u9 a' L9 s- R
sync = self.process_network_devices(device_info)
5 R4 z$ ^5 E% @8 ~ except Exception:
# ]7 e) M) H2 @: a w6 r6 P3 i LOG.exception(_LE("Error in agent loop. Devices info: %s"),
) q2 L% j# h* h- G; w2 w device_info)
% P, c- u1 m8 F1 f" d' p! e sync = True* {: ]$ n; y) y: q* D
% s+ T( D. b9 ~, j+ C这是它首先找到的 devices: c/ \! L F3 M$ H0 b: i. g. K+ \
(Pdb) p bridge_lib.get_bridge_names()
( m. B2 o8 ~/ z; ?['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'] Z, P4 i* \: x& ?- t C5 K
然后过滤出 tap 设备:
, K# ?+ Z3 o2 e' n( G4 Z/ Tget_all_devices()->set(['tap0bb8efeb-10', 'tap60dbdc2f-a0', 'tap795e6e86-94', 'tap798c87d1-a2', 'tapb1eaae00-e5', 'tapf70543dd-0f'])) i3 A' ~& h* ]# F P1 D
(2)根据 previous 中保存的历史数据,再接合服务器端和本地更新时间,计算出需要更新的tap设备列表:$ T- ]9 @& t' o: z2 l: u
{'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([])}" p# w1 k* F5 U' H- q3 z8 T. {: b
(3) 通过 RPC 获取 tap 设备的详细信息& _' g' a" Z* _5 _: k* F: a
3 A8 U# R3 N, Y# d
(Pdb) p devices
$ T8 n/ w8 D+ H9 |set(['tapf70543dd-0f', 'tap60dbdc2f-a0', 'tapb1eaae00-e5', 'tap795e6e86-94', 'tap798c87d1-a2', 'tap0bb8efeb-10'])
1 r0 L2 B0 H1 a* y. T: p* V5 ? I! `: m/ ]2 i( D/ B
6 O. c8 I8 L; b7 n
devices_details_list = self.plugin_rpc.get_devices_details_list% K; v H# J7 j7 H6 y, U% A
8 p1 v/ ~) o3 ~5 [; o$ B2 L
(Pdb) p devices_details_list9 B! t# W* A$ @
[{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': []}]7 E% K# V; o/ k2 Q* s E# v. r, I
" Q- h1 P0 ~0 ^* W
(4) 对需要处理的设备,调用 self.process_network_devices(device_info) 函数进行处理
! o6 H1 A+ ]9 S. \/ |) U. i# Q(5). 调用 plug_interface! _9 Z* E$ T; I
interface_plugged = self.mgr.plug_interface(network_id, segment,device, device_details['device_owner'])
+ ?$ H3 Q% ]4 s$ @(6). 需要的话,使用已经配置的或者新建 linux brige,并将 physical interface 设备加入其中
9 Y& _. k0 v. ?3 J7 D$ o/ Q1 }6 Xbridge_name = self.get_existing_bridge_name(physical_network) #获取为 physical network 配置的 linux bridge
$ |. Z4 ]2 P* B; m8 t6 kbridge_name = self.get_bridge_name(network_id) #或者根据 network id 生成 bridge name
4 l8 X' W# A: j: U n# M) l(7).根据不同的网络类型,分别处理 vxlan bridge,flat bridge 和 vlan bridge
0 c$ O4 k& l6 p: _* X: l& w. l6 j6 @
0 l) h, L& F' S2 _" ?: C, I, h; R def ensure_physical_in_bridge(self, network_id,
6 H2 P+ h+ D4 p. {! I network_type,* @+ u" o! M) C# _0 R6 y
physical_network,
: e* Y: D8 h$ N3 @ segmentation_id):3 U8 t7 a7 \" d# l) g7 E
if network_type == p_const.TYPE_VXLAN:
5 [6 K) t8 ^" c) Q t. w9 L+ Y6 U/ l if self.vxlan_mode == lconst.VXLAN_NONE:4 b) Q& z% W4 H# q
LOG.error(_LE("Unable to add vxlan interface for network %s"),
% y/ ]1 D8 ]+ q7 @; P; T network_id)
3 P& y3 m4 g* k. l return* W: r" a* ~7 B+ v, |3 R& F
return self.ensure_vxlan_bridge(network_id, segmentation_id)( X8 Z% V+ G& o7 f: c
. M$ j- z2 K" g- z # NOTE(nick-ma-z): Obtain mappings of physical bridge and interfaces( M. l r% U6 ?+ h4 V
physical_bridge = self.get_existing_bridge_name(physical_network): @( U8 {- ]* E9 U/ \( C
physical_interface = self.interface_mappings.get(physical_network)
3 z( M' [ Y. |0 K1 t0 f if not physical_bridge and not physical_interface:; {3 X3 C7 e5 ~0 t' [
LOG.error(_LE("No bridge or interface mappings"
& m9 h% w' i4 q9 R) @, X " for physical network %s"),
0 {8 {* f5 m+ c physical_network) l. m V B) S" @; a G
return2 o! x7 t7 }( W
if network_type == p_const.TYPE_FLAT:
- T3 a- D/ G: G$ X$ s return self.ensure_flat_bridge(network_id, physical_bridge,+ o4 ?8 m/ O8 z9 O8 w2 _! V- ~
physical_interface)
8 E$ m- X+ W. z' ^+ a# d elif network_type == p_const.TYPE_VLAN:$ e/ p8 A% {4 F; n1 T! q
return self.ensure_vlan_bridge(network_id, physical_bridge,
4 \" I6 t3 i2 V5 h$ a y physical_interface,
" _( \0 f! p- P7 D( e segmentation_id)
, v+ }( x$ }/ `5 g5 A
% @* S. D7 _( W4 Z9 v: M对于 flat 类型的网络,调用 ensure_physical_in_bridge
1 t( C" F5 r' P7 p8 Q; l4 rdef ensure_physical_in_bridge(self, network_id,network_type,physical_network,segmentation_id)
, N% \% R& R% U! m* n6 @+ A if network_type == p_const.TYPE_FLAT:
/ l% o, ]& F1 w return self.ensure_flat_bridge(network_id, physical_bridge,physical_interface), E+ w. @2 P- R. q6 l( l
如果有配置 physical bridge 的话,使用它;否则创建 bridge,并将物理网卡配置的 ip 地址和 gateway 从网卡挪到 linux bridge
! x( Y+ C$ P( B, ?% P: @
; w, W" L: L5 j& {; Rdef ensure_flat_bridge(self, network_id, phy_bridge_name,physical_interface):* Y4 l$ ~& x/ s7 j6 P! n3 O$ H! v. r5 | r
"""Create a non-vlan bridge unless it already exists.""") m7 z& ?5 g4 X( |3 B6 @
if phy_bridge_name:
, V' k: B( W/ E4 A0 G' I6 E return self.ensure_bridge(phy_bridge_name) #获取预先配置好的 linux bridge# k7 s/ O4 z/ V7 z
else:% |( F5 ]. d0 @6 l" @% G6 f
bridge_name = self.get_bridge_name(network_id)7 S6 s+ w' f+ k @% ~0 h9 p) W$ h. B
ips, gateway = self.get_interface_details(physical_interface)
! T1 v7 _4 q& N* B% q if self.ensure_bridge(bridge_name, physical_interface, ips,gateway): #创建 bridge
: M% _7 k3 O0 q return physical_interface6 G0 R" g& I! A8 P* m
! i7 N5 U% x+ p( T6 S1 q4 M
对于 vxlan 类型的 network,需要创建 vxlan interface% d$ s& f7 X$ A4 N/ Q& f
5 K. `' P) K4 M, D" p5 B3 X2 c7 `& ^6 c
def ensure_vxlan_bridge(self, network_id, segmentation_id):
, {3 l$ _+ B7 s. m) g" s0 n* X x """Create a vxlan and bridge unless they already exist."""- ^2 _4 u+ T, W
interface = self.ensure_vxlan(segmentation_id)
. g# z. c) R0 f if not interface:
4 j& W: U8 t/ f$ G LOG.error(_LE("Failed creating vxlan interface for " w( j8 J# \9 c n) b: {# t
"%(segmentation_id)s"),
* E4 S" f) w$ x- F7 J9 c3 m {segmentation_id: segmentation_id})
! a9 x6 f) }8 y5 z7 M. n' J7 H. F return' I* |7 {# u& f8 a
bridge_name = self.get_bridge_name(network_id)
' N$ _- z7 Q, u self.ensure_bridge(bridge_name, interface)
2 Z6 W) h: O- M1 q7 s return interface
/ ^ Z% s6 M& x! S4 u 9 Z% W4 `" ]! ?( w' Z/ i
创建 vxlan interface:
/ C& o0 ^) Y5 O& B 1 b \- b. Y& A3 |# ?+ D
def ensure_vxlan(self, segmentation_id):
" {: s8 j J/ F, m* ?* p1 {5 d1 J- e """Create a vxlan unless it already exists."""/ {1 u/ T ~# n8 ~$ k' h5 ^
interface = self.get_vxlan_device_name(segmentation_id)5 o$ p0 f5 v* J( p
if not ip_lib.device_exists(interface):8 ~& R0 n k0 C
LOG.debug("Creating vxlan interface %(interface)s for "' Z' L) E- {6 c6 `% r
"VNI %(segmentation_id)s",( S. k0 r* l+ g: E6 N7 e8 {
{'interface': interface,
& h$ p3 V( X B$ {! | 'segmentation_id': segmentation_id})
, m& ^7 U4 ^/ ~/ t args = {'dev': self.local_int}# U2 i8 Y5 }; q, H( A
if self.vxlan_mode == lconst.VXLAN_MCAST: @* |! O4 n) y4 ~, q+ g7 {
args['group'] = self.get_vxlan_group(segmentation_id)
2 m* }* V T5 |+ x- i E if cfg.CONF.VXLAN.ttl:
" H9 E- p W2 C+ ^; k args['ttl'] = cfg.CONF.VXLAN.ttl: D: U& h& n; l* e: k
if cfg.CONF.VXLAN.tos: Y2 ?5 g& x/ ~, T- c) r$ E! X
args['tos'] = cfg.CONF.VXLAN.tos8 C- a; k! G8 S) g- W$ ?& R
if cfg.CONF.VXLAN.l2_population:
9 W5 Y0 A3 C) N+ M, B; C: l args['proxy'] = cfg.CONF.VXLAN.arp_responder- @$ O3 i$ E$ ~; \( Q- t$ X
try:
& C. P. `" }; }- V, G int_vxlan = self.ip.add_vxlan(interface, segmentation_id,$ j% `+ }9 _0 `* W
**args)
! F3 E7 m4 _ u% ?" c- R
4 h3 `0 L" G. U' |: K(8). 将 tap 设备加入到 linux bridge 中' S* P9 Z/ z. V
bridge_lib.BridgeDevice(bridge_name).addif(tap_device_name) j! R2 j1 O1 F/ C
(9). 如果将一个 tap 设备被删除,那么 linux-bridge-agent 会发现:6 k3 ~6 Q5 a [; q1 i
2016-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'])+ I: _) J* {" n
2016-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
$ p0 L( T1 Q) `. m4 `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.
2 g+ Y- a; Z f4 B5 h# K$ ]5 l3. 关于上述工作过程的简单结论
6 ` V* y8 l! L0 k# l/ N3.1 简单结论
( T9 e$ ~+ L, ?$ u& X1. l3agent 和 dhcpagent 创建 network namespace 时创建 tap 设备,和 network namespace 中的 interface 是一对 veth pair。当手工删除 tap 设备时,相应的 veth endpoint 也会被删除。. E3 q! W. k) P- g9 `
2. linuxbridgeagent 不断扫描服务器端和本地的 tap 设备6 X, s! }: C% q8 Y2 p
3. linuxbridgeagent 获取需要增加和修改的tap设备列表2 N9 B2 a- M- B9 j. w
4. 对于需要增加的 tap 设备,获取其详细信息,主要是 network_id,network_type,physical_network,segmentation_id,device_owner 等,然后根据这些信息,创建 linux bridge,并加入所需要的 interface" N3 d+ h% u! o# F! |% `+ G2 [
5. 创建所需要的 linux bridge,并将 physical interface (provider network 的 physical interface 或者 tenant network 的 vxlan interface)加入 bridge,并且将 tap 设备也加入该 bridge
3 U5 P" |8 x4 ^- s* L! @6. 如果发现某个 linux bridge 没有创建出来,首先需要查看有没有相应的 tap 设备存在;如果 tap 设备不存在,则查看相应的 qdhcp 或者 qrouter 中时候有interface
4 }4 X% r. Z @% m3 ^9 n
/ y5 [0 g: ~! ~3 {# f) Z具有多个 VLAN 租户网络时候的网络元素示意图:
% q* U1 {( b/ v ! e) R e& P; O+ U
; s' u2 I0 H& y: @
% M& n' l, e K3 W
! p1 Q# Q) [7 p" [2 |9 D# t 3.2 关于 unnumber interface! k. B5 x* Y! k: w$ n
OpenStack 官方的 host networking 配置中,连接外网的 interface 可以是 unnumbered 的,从字面意思理解,就是该 interface 上不需要配置 IP 地址。
8 n' W2 \6 g2 X, @+ c 0 y7 J3 `2 A2 X7 s5 i1 C7 Y. o
配置的时候,修改 /etc/network/interfaces:1 }; k0 ^4 `# }# p5 H0 n+ ?& [/ L" V
# The provider network interface
: f# Q( P. W1 T0 x bauto ens224
) _% X$ u, o+ ]! c% Z' J7 |+ Xiface ens224 inet manual( b; o! f$ \# W
up ip link set dev $IFACE up
# ?9 y8 i* L% M9 i" U9 k" r& L- Hdown ip link set dev $IFACE down
; H0 s; i0 h9 S! N1 _4 }配置好以后:# |0 C& B. J& S& g
2 }4 r' @& n j2 J' t3 \0 P6 S7 eroot@controller:/home/sammy# ifconfig ens224
( T4 K8 Z: M$ W, t* kens224 Link encap:Ethernet HWaddr 00:50:56:9c:4d:94
2 M5 X" b0 {4 S UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
3 Z( a% J" g0 M; L( Y3 i RX packets:27300737 errors:0 dropped:0 overruns:0 frame:0, P& q/ g+ ]+ O2 r0 n+ I
TX packets:61547 errors:0 dropped:0 overruns:0 carrier:0% E# a7 l" N! |' A
collisions:0 txqueuelen:1000
5 l X8 d: @& Y1 j) x RX bytes:31951077598 (31.9 GB) TX bytes:5966060 (5.9 MB)7 L# _- I; B# |) w8 s
1 z/ m( j" p A* {( C ?+ ^ Sroot@controller:/home/sammy# ifconfig brq96609bfa-0e2 x# y3 @/ e8 F& r
brq96609bfa-0e Link encap:Ethernet HWaddr 00:50:56:9c:4d:943 C- K) _ r" d. e
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
0 B4 o4 H2 T/ b! i RX packets:32855 errors:0 dropped:0 overruns:0 frame:0
. r$ k! [2 m. Y2 l TX packets:2 errors:0 dropped:0 overruns:0 carrier:0
; X. K; o! t3 B3 G" R% O collisions:0 txqueuelen:1000+ T) }# o: q! ~) z5 c) {6 ?
RX bytes:2731030 (2.7 MB) TX bytes:84 (84.0 B)
& g8 F3 q" S" {
$ y4 f N6 T+ s; J; p! a6 E具体原理不详,但是应该是因为 qrouter 的 qg network interface 和物理网络中的路由器的网卡之间是网络二层,因此中间的设备都是属于二层的,因此不需要处于网络三层的 IP 地址。/ J6 |3 I/ ~: T1 G! x/ K! c
4. 使用 linux bridge 时的拓扑结构
0 V4 g- ^8 ^; q' T8 c) z; o* |" C; q4.1 网络节点上
# i1 v) |' g0 A4 \为了更清楚,我们来对比着看 linux bridge 和 ovs 的两种方案:
/ z+ P8 H6 E. ~, qlinux 方案:
t% Q8 m2 L# B# \% @ 9 p* m9 b( o% J' U( J. T; G0 c3 @
网络服务:' c$ Z8 H# z r) U* x) x
• Linux bridge agent
$ i" T' j2 H( j7 r+ M% k! ^9 B. G• L3 agent* m' m9 Z2 q k4 n& C& V: b
• DHCP agent8 B& H" |4 t7 I$ b2 g
• Metadata agent8 E+ J5 A3 [/ e& \- d6 G& h8 I/ A; h! u
Linux bridge agent 会为每个 VLAN 虚拟网络创建一个 VLAN Bridge,它连接多个网元:
$ Y8 z( }9 U* S, b' D. y+ l7 Q. f5 J• VLAN 子接口,从物理网卡(图中的 interface3)上创建,每个子接口对应一个VLAN ID,其名称格式为 device.sid,其中 device 是物理网卡名字比如 eth0,sid 是 vlan id。
4 T" S! I; p" {3 ~- d& \- I: y• 连接虚拟机的 tap 接口
- D1 e* ^) j7 n) W7 m7 V• 和 qrouter 连接的 tap 接口! J" `2 G* R8 |8 `0 Q
• 和该网络的 qdhcp 连接的 tap 接口, F: @9 E; @/ |# f* r; U* G
如果同时有 VXLAN 虚拟网络的话(linux-bridge 不支持GRE 隧道模式),会为每个 VLAN 虚拟网络创建一个 Tunnel bridge。它连接多个网元:
, u1 @ |+ s5 V• vxlan interface,这种接口每个虚拟网络一个,名字格式为 vxlan-sid,其中 sid 是分段ID。2 I- R: p. F" ~5 T* k w4 A$ `
• 连接虚拟机的 tap 接口
7 H I6 t9 }8 R, c& T• 和 qrouter 连接的 tap 接口0 U- C: ^% C$ y0 t5 [* J2 k8 o
• 和该网络的 qdhcp 连接的 tap 接口1 k: E/ F4 j# H+ v& U
安全组规则在 tunnel bridge 和 vlan bridge 上。 M6 |* L7 J! O# Q* e" C1 ?7 i
OVS 方案:, ?' r* v9 s: x/ Z
. X' N2 q- a; `8 A& S7 x3 m O" G. d
这里面,br-int 会负责加本地 VLAN 标签,br-tun 会负责将 VLAN ID 转换为 VXLAN ID。
@) i6 }' h+ J
6 W6 i' D T* ^0 q2 O4.2 计算节点上+ Y J- L. [; i& j
同样来对比着看。7 f; a+ B ~, P% S0 x
linux bridge:( ^* Y& h B. E3 [* a
7 v; x+ H+ t+ l% d. o I: G
网络服务:! H( }! q; T7 O. f5 c' P8 d" g
• Linux bridge agent7 P4 K7 G3 [8 c, @
和网络节点类似,只不过没有 qrouter 和 qdhcp,不在赘述。
% Z9 F5 Y$ X8 _OVS:/ b2 {! a, n U
; i# v m. a1 Q5 V2 l
2 j& H+ n0 a2 G1 o; COVS 放在在 br-int 上实现 VLAN 标签,在 br-tun 上实现隧道,在 qbr linux bridge 上实现安全组。8 ^" j" X1 [' q2 E/ Z+ t+ ?
3 T2 O# V1 R4 y3 |1 K+ I; {8 C4 B
4.3 网络路径 - 南北向网络流向
) v# ^, B% k9 G3 ?
7 M) i. j3 C" k0 ?) e& k' QVLAN 网络和VXLAN 网络井水不犯河水。这图上的配置中,计算节点和网络节点上的物理网卡都分开了。
_' M, ]$ _0 _6 a0 u& I; W5 Y5 `4.4 网络路径 - 东西向(不同网络)
! w/ O- L0 |( S4 m7 T" n8 L " ]3 t* d/ M% [3 L( i/ J3 s8 X' `
4.5 网络路径 - 东西向(同一个网络)4 b6 n9 q, u6 Q- r' c6 P
/ b; P; j/ I l# g7 d7 b 5 c0 u( Q8 w) O: B) k4 o6 U
请详细说明和配置,请参阅参考文档。
4 w4 t" W& Z$ @& h, w5. 一点结论
4 H7 Y/ W! r9 U和基于 OVS 的二层网络相比,
. |' \8 V' y. E6 o" g/ J• 功能和架构上:基于 linux bridge 的实现还是有一些短处,比如每个虚拟网络就需要一个网桥,这在大规模环境中会带领资源使用和管理上的问题。其好处是本身架构比较清晰。
* x4 L \1 k6 y4 r: N• 性能上:基本上差不多,如下图所示,不管是 vxlan 还是 vlan。0 X+ T# g, o- v( U9 W% C7 E
2 r0 t/ C: L6 o/ \& p, f8 u# {
' U) ?% x; w6 K: x3 v
|
|