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

楼主 |
发表于 2019-10-25 11:23:29
|
显示全部楼层
虽然大部分的OpenStack 部署环境中,都会使用 Open vSwitch 来作为虚拟交换机来实现二层网络功能,但是Neutron 仍然支持使用 Linux bridge 作为虚拟交换机来实现二层网络。本文就此做些分析和说明。
* P3 i, M3 u; V# m5 a' Q同时要指出的是,OpenStack 官方已经把 linux bridge 实现标记为 legacy 的了,文档从 2016 年后也没怎么更新了。这是因为,linux bridge 和 OVS 相比,只支持基本的网络功能即二层交换,但不支持VLAN 标签和隧道。因此,linux bridge agent 利用linux 内核功能(VLAN 子接口和 VXLAN 接口)来实现VLAN 标签和隧道。
0 [/ V. _ {1 C$ H6 p2 I6 k 7 t) f( A) U0 q% m7 _
1. 测试环境* ?3 T$ L- P$ \" b! i2 B. W
以下面的环境为例(网络节点上):" h; s2 Q- z Q+ I* [6 G# a
(1)linux bridge- o! v& r) I+ ?: i, ` `
8 f/ a) | N5 C
root@controller:/home/sammy# brctl show/ [/ g; g- i' v% }( ~, I. ^
bridge name bridge id STP enabled interfaces% S) M$ o5 H( T* v" z% `
brq85925305-b4 8000.563534c8d02d no tap0bb8efeb-10
3 }0 I3 u2 t j" `4 V, \9 r tap798c87d1-a2
7 e( |3 L. J! x L8 U! p vxlan-25
/ r% e5 p5 J; I8 Y- rbrq96609bfa-0e 8000.0050569c4d94 no ens224* d( Y) \( F5 B U# ~/ j* [# p
tap60dbdc2f-a04 U/ r: ]& a. D1 Q. K
brq971ffda2-e5 8000.a6acb08e4fd6 no tapb1eaae00-e5
# R2 `* O! ]; g( Z# J tapf70543dd-0f
- R" `9 }( ?1 f$ N* K0 { vxlan-10& |! O1 ~1 W: y$ w0 S
8 v2 _' ~# I; n" w, p" o; v
(2)OpenStack 网络和 network namespace:
+ x$ Z5 I0 O! Q- |# z * b( M" n! ?" R& r/ E$ i2 O, V
root@controller:/home/sammy# neutron net-list
9 c7 l+ I0 ~# F) h1 N$ b6 I+--------------------------------------+---------+-----------------------------------------------------+
- L. k& N5 r5 S0 b| id | name | subnets |* R3 H2 F8 @9 v; {# S
+--------------------------------------+---------+-----------------------------------------------------+- @9 }: r: g6 \" [
| 96609bfa-0e22-4bb7-8dba-6ef532ea6076 | extnet | afa7d205-3026-439f-aca7-295a9f9b2a71 10.62.227.0/24 |8 G9 ^& T3 G# `
| 971ffda2-e567-40a0-a2c8-b31a577fd4d3 | appnet | 4c68eacb-bf3e-408a-a941-94e93eddb22b 11.0.0.0/24 |
6 w3 `7 F( Q- W) N! g: U| | | 3d596991-de8f-4ae4-8913-89426a8abbd7 10.0.0.0/24 |
5 _! X6 S3 l e| 85925305-b477-4cc6-9654-67d9bf1e7cd8 | appnet2 | 4575c7f1-7f08-4917-9904-ec65af38619b 20.0.0.0/24 |
i# s0 S/ G1 q/ \+--------------------------------------+---------+-----------------------------------------------------+1 T, S' Z+ E: b0 `$ z3 _+ ^' b: m
root@controller:/home/sammy# ip netns \4 M/ e8 Y1 s2 W. e! g" |
qdhcp-85925305-b477-4cc6-9654-67d9bf1e7cd8 (id: 2)+ o7 V1 L2 D. i( T1 F# H2 F
qdhcp-971ffda2-e567-40a0-a2c8-b31a577fd4d3 (id: 1)" Q: A. W6 ^# a7 \& B0 R
qrouter-39a77439-8a28-49c1-bf97-ac931510631b (id: 0)/ o' u: n# t( e7 k$ G& e; o
; }' }9 U) {, i4 {, ~(3)示意图:8 K: |$ @1 ]- U& U3 L
: R1 [7 d5 p% P
(4)说明:
; V# e+ Z8 g2 f% L% m* `. s4 r. M• qdhcp 和 qrouter 都是 linux network namespace 实例4 v( \1 k" ]7 \5 F
• qdhcp network namespace 的数量等于启用了 DHCP 的 Neutron network 的数量。
2 E# _# I/ Y4 V# X$ `o 当一个 network 中存在至少一个 subnet 启用了 DHCP 之后,会有一个 qdhcp network namespace 被创建出来;( ?' m# H7 g6 `1 f
o 当一个 network 中多个 subnet 启用了 DHCP 时,它们共用一个 qdhcp,以及 dnsmasq。; _0 ]5 a ?) q3 ]
o 其 name 使用 network id,比如 qdhcp-85925305-b477-4cc6-9654-67d9bf1e7cd81 n7 a; Z% N: q
• qrouter network namespace 的数目等于 router 的数目,也就是说,系统中一共有几个 router,那么就存在几个 qrouter network namespace
0 T5 [8 e* l; o6 A; A: V8 j5 v• brq linux bridge 的数目等于 neutron network 的数目,其 name 是 network id 的前几位,比如 brq96609bfa-0e
. k7 H8 E8 k. ~8 @2 v- ?7 u1 X• 一个 network 的 qdhcp network namespace 和其 brq linux bridge 一定有连接* K- y4 b o* s$ W- c/ I
• qrouter 之内的 network interface 分两种,一种是 qr 开头的,每个连接到 router 之上的 subnet 都有一个;还有一个是 qg,每个连接到 router 的 external subnetwork 有一个
- f- N9 C: A# X' e: s• qrouter 的每个 network interface 都通过 veth 连接到所在网络的 qbr linux bridge 上* c$ V1 ^ t( d# J
• qbr linux bridge 连连接两种物理设备,一种是 vxlan interface,每个 tenant network 有一个,另一种是在 physical network 对应的物理网卡上创建的子接口(sub-interface)- |1 U& q7 m2 [* C4 B
• 对于 physical network 的 qbr 来说,用户可以指定它,并且在linuxbridge_agent.ini 中通过 bridge_mappings = List of <physical_network>:<physical_bridge> 进行配置;也可以不指定,此时 agent 会创建它。当同时配置了 physical bridge 和 physical interface 时,前者优先。* p; i1 [5 W8 Z. j- ?, ~& G
如果 external network 中有多个 subnet 的话:1 Q) C; ]/ W7 l& W! a( g1 d! S0 C
(1)每个 qrouter 只允许有一个 External Gateway,也就是说它只有一个 qg network interface。当 external network 添加多个 subnet 之后,只有第一个被当作 external subnet,其余的都会被当作 internal subnet。2 K7 i2 U- e. }
(2)在 qrouter 的路由表之中,9 g, [7 K- U' j0 ~5 g9 Q% z: ^* A
3 W2 P3 G0 c" f6 zroot@controller:/home/sammy# ip netns exec qrouter-39a77439-8a28-49c1-bf97-ac931510631b route$ [/ G; k$ P& s( @; c
Kernel IP routing table) E& b9 i8 z1 y' w1 L
Destination Gateway Genmask Flags Metric Ref Use Iface6 B: W _7 [- _- {3 J
default 10.62.227.1 0.0.0.0 UG 0 0 0 qg-e09fce07-cd: ?$ @# ]7 s/ r7 _9 V
10.0.0.0 * 255.255.255.0 U 0 0 0 qr-b1eaae00-e5
, [# v$ v S# N8 o10.62.227.0 * 255.255.255.0 U 0 0 0 qg-e09fce07-cd# N ]% N/ [* s6 [
10.62.228.0 * 255.255.255.0 U 0 0 0 qg-e09fce07-cd
8 b6 h. f' R0 r! V/ U" G10.62.228.0 * 255.255.255.0 U 0 0 0 qr-124ff148-b7
! i2 c4 |/ o% a6 d* j7 |1 b11.0.0.0 * 255.255.255.0 U 0 0 0 qr-16d9b0cc-38
; [. r7 V) e0 N6 C* A20.0.0.0 * 255.255.255.0 U 0 0 0 qr-0bb8efeb-10* m/ t8 [% h, h' ?: Y; d! ]
) v2 v5 e2 c# }! [7 b! R2 p
; \4 r$ U6 l U$ L& G2. linux-bridge-agent 工作过程分析) g3 h6 `' I; R n
(1)linuxbridge-agent 会启动一个循环,不断扫描上面红框中的 tap 设备
4 y% n5 A. C& X9 p) n6 h. }4 g' r$ y8 C 7 D7 ?; ~9 M) J* _) W. M7 Q/ e# d c
def daemon_loop(self):
' c) S1 k( w5 L# E/ l, c' F9 I...3 W! |( F. L- @( X8 _" A3 x
while True:* |6 H7 U1 T D8 b
start = time.time()
" y+ ^ }% O7 K. ..' L6 {7 p/ V O9 W
0 ]0 {9 M) j a1 |. G* K# t
device_info = self.scan_devices(previous=device_info, sync=sync)8 n+ J5 S+ j& l0 M- U* [1 O
sync = False D. h# s, J# {( @
1 K3 s1 T3 x" |) L4 d if (self._device_info_has_changes(device_info)
- G E6 I/ v$ K( l+ ? Z6 h. q or self.sg_agent.firewall_refresh_needed()):
$ i# y5 z; A9 j' E" B LOG.debug("Agent loop found changes! %s", device_info)
+ U6 p3 s% l& O8 P- @; Q$ k7 u6 y try:
+ s; [* {8 i* g O; L sync = self.process_network_devices(device_info)$ U* r8 J7 G9 [* G0 }' m
except Exception:% j+ {' I* ?! u2 `9 |+ [ _7 h9 F
LOG.exception(_LE("Error in agent loop. Devices info: %s"),4 ]. f- Q7 |3 @/ |' @4 f9 _
device_info)
3 b6 n* I$ @; A- f! K4 W4 U sync = True# r3 q( _5 z* D/ U1 L4 q
7 X+ {# h$ _+ I' J9 g( G这是它首先找到的 devices:
$ x% g- q/ F$ G(Pdb) p bridge_lib.get_bridge_names()( }1 H/ |4 e3 s" _3 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']
! ~6 z! d0 A9 t$ }/ B然后过滤出 tap 设备:
, i: ^$ Y. M+ r8 J, e3 p" I# R( Lget_all_devices()->set(['tap0bb8efeb-10', 'tap60dbdc2f-a0', 'tap795e6e86-94', 'tap798c87d1-a2', 'tapb1eaae00-e5', 'tapf70543dd-0f']); s' n4 h$ B; C$ j0 f
(2)根据 previous 中保存的历史数据,再接合服务器端和本地更新时间,计算出需要更新的tap设备列表:
6 {) l: t6 c# i. s* r{'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([])}: i6 u4 ?2 q( s+ ]8 t3 B, N
(3) 通过 RPC 获取 tap 设备的详细信息
0 J/ x+ [% j# u& T/ D 2 e) s) v' R5 H, W* e
(Pdb) p devices
* o& n$ n% H. s4 K4 a- Wset(['tapf70543dd-0f', 'tap60dbdc2f-a0', 'tapb1eaae00-e5', 'tap795e6e86-94', 'tap798c87d1-a2', 'tap0bb8efeb-10'])- z# @3 \% g7 E4 j
, p- ?* y0 N5 o. W4 E+ q4 F; j% _+ l
! @5 g0 }# P5 Y* M4 p0 f2 U/ @devices_details_list = self.plugin_rpc.get_devices_details_list
J$ p) q* e5 W# M
7 f4 c8 J! j/ y* }7 n8 ~(Pdb) p devices_details_list9 J' U% g) k5 U2 {
[{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': []}]
: ]6 \$ A7 c$ [" l q4 q 2 G' Y6 t% C+ W1 d/ o- O
(4) 对需要处理的设备,调用 self.process_network_devices(device_info) 函数进行处理: u b0 L% Q3 b+ ]* X! K& Z1 c
(5). 调用 plug_interface
& w7 P( i9 D1 x. v9 kinterface_plugged = self.mgr.plug_interface(network_id, segment,device, device_details['device_owner'])
3 V! C# M- T- Q(6). 需要的话,使用已经配置的或者新建 linux brige,并将 physical interface 设备加入其中 x' |' W! q8 ?; t& f
bridge_name = self.get_existing_bridge_name(physical_network) #获取为 physical network 配置的 linux bridge
; a$ w9 Z0 T) b- V8 Zbridge_name = self.get_bridge_name(network_id) #或者根据 network id 生成 bridge name/ \1 Y+ X5 X! p+ ]
(7).根据不同的网络类型,分别处理 vxlan bridge,flat bridge 和 vlan bridge. X9 N2 c+ j3 e
/ v% V" ~ o7 q y0 X! c- f
def ensure_physical_in_bridge(self, network_id,
( K. a3 X7 k( B4 f9 C/ } network_type,: Q9 ] L2 E3 w$ i2 |& w
physical_network,/ r: J5 F2 T& q o, {
segmentation_id):
T# }9 [" h7 r if network_type == p_const.TYPE_VXLAN:
4 P" H8 S$ T! {3 d% D# F if self.vxlan_mode == lconst.VXLAN_NONE:
% @2 |8 J* ~8 O: { LOG.error(_LE("Unable to add vxlan interface for network %s"),8 i) c# f2 ^, ~7 n) ~8 L. H
network_id)
' k+ j+ e& w# K7 m1 |; e! M9 m7 [ return
% o* s4 d$ V) M- q# ?% M8 X" E4 Y return self.ensure_vxlan_bridge(network_id, segmentation_id)" k0 R9 Z6 N# N( ]9 X; N
" ?; }" |0 s: ]( ~7 p9 X- P # NOTE(nick-ma-z): Obtain mappings of physical bridge and interfaces
9 `5 ^: r* [5 E2 i physical_bridge = self.get_existing_bridge_name(physical_network)
4 u# y7 o3 k a8 | physical_interface = self.interface_mappings.get(physical_network)4 p- |, y& x& G
if not physical_bridge and not physical_interface:
- ~( f/ _, g& S! d; t% _ LOG.error(_LE("No bridge or interface mappings"0 J! j% D0 }: ?! F5 @3 O: ~( V
" for physical network %s"),5 j6 J' Q% k/ d9 |* o
physical_network)
2 m9 r+ d2 X, `" }3 w- O4 Z4 g: f return0 l7 y0 @8 t% Q2 j h
if network_type == p_const.TYPE_FLAT:% [9 E- N* P7 ~6 I
return self.ensure_flat_bridge(network_id, physical_bridge,6 w5 V0 b2 ?9 l3 q5 S) m$ a
physical_interface)
. g& i7 l. ]4 k6 j0 { elif network_type == p_const.TYPE_VLAN:; r+ c0 v7 }6 L
return self.ensure_vlan_bridge(network_id, physical_bridge,
+ Z; _% c8 g8 w$ J! Z physical_interface,
0 ]. d8 q/ E q) j# M) V) J segmentation_id)/ B9 u( }5 ]# Z+ O9 J2 Q/ E3 R
: }# B& h/ X1 n# O; {
对于 flat 类型的网络,调用 ensure_physical_in_bridge5 C$ }2 _3 [3 j& [
def ensure_physical_in_bridge(self, network_id,network_type,physical_network,segmentation_id)+ b9 {8 K( j) b9 |$ e
if network_type == p_const.TYPE_FLAT:
& u. `; p! K0 ~' Q return self.ensure_flat_bridge(network_id, physical_bridge,physical_interface)4 V$ V) Q: d5 J! _! ]
如果有配置 physical bridge 的话,使用它;否则创建 bridge,并将物理网卡配置的 ip 地址和 gateway 从网卡挪到 linux bridge
) W; Q/ e: ~2 q- v
! i5 P; l8 U2 mdef ensure_flat_bridge(self, network_id, phy_bridge_name,physical_interface):5 Z$ _) t( z! B# X. w3 C- ]
"""Create a non-vlan bridge unless it already exists."""
% z \, f7 J% |$ I" w- v& N if phy_bridge_name:# y' h. h# K$ ]& Z8 R
return self.ensure_bridge(phy_bridge_name) #获取预先配置好的 linux bridge+ l( @/ h& P' C2 p0 Y
else:
% ]- C, O( G" K! p" d* g bridge_name = self.get_bridge_name(network_id)0 G; n1 `2 k A8 j) O5 E" P% N
ips, gateway = self.get_interface_details(physical_interface)1 ~( b# N; {' Z% a2 C& v
if self.ensure_bridge(bridge_name, physical_interface, ips,gateway): #创建 bridge! A7 J6 w5 c! N5 [ t
return physical_interface$ }4 K! o; ~: ]" Z' h4 z
( @, ?5 W6 w8 _1 J& a' K; p: s
对于 vxlan 类型的 network,需要创建 vxlan interface0 [0 g: \7 R% o3 }! S) j6 Z
, `2 C( E* I/ i! ^& Z" q
def ensure_vxlan_bridge(self, network_id, segmentation_id):
- t2 G( K4 P: [6 I( {) t8 S" G """Create a vxlan and bridge unless they already exist."""" y1 Q3 v" H$ o# y2 Y
interface = self.ensure_vxlan(segmentation_id)2 G; u3 E& g3 K* z6 z
if not interface:
+ p2 r( Y/ l% e5 v9 ] LOG.error(_LE("Failed creating vxlan interface for "
3 F% q" ]. U9 G. n, i: z2 D "%(segmentation_id)s"),
1 @8 ?% T M' G5 l1 M' a9 S t* X {segmentation_id: segmentation_id})
2 T/ ?5 f* H& n1 e: o. b. ^5 h4 ` return
& l* T. {- q% p bridge_name = self.get_bridge_name(network_id)3 y/ W% v" O! Q; D; ]* O& s% ^
self.ensure_bridge(bridge_name, interface)
; r( S2 A. U1 q% T* H return interface
2 j% ^# M: c( ~) B 8 [ p, R0 u+ T2 U( |9 u3 z
创建 vxlan interface:% Q. e. Q3 p6 R" w
3 N. {- ?8 B X% `; `* W def ensure_vxlan(self, segmentation_id):
6 H7 p* C# X" d( d" E """Create a vxlan unless it already exists."""
& V/ s( i, A! g2 `- \ interface = self.get_vxlan_device_name(segmentation_id): K0 R: |+ b; G* u- z! h0 {0 c- s
if not ip_lib.device_exists(interface):
, o) K& B+ {3 k* _0 q LOG.debug("Creating vxlan interface %(interface)s for "# v, N% b$ c( U' R2 c% i$ |
"VNI %(segmentation_id)s",5 o1 g: P" p& C2 a4 t6 g
{'interface': interface,8 ?. X; L- F+ s& \5 E b* \
'segmentation_id': segmentation_id}), p9 w9 ^" J8 F7 w7 w
args = {'dev': self.local_int}1 Q% h& S# I$ a1 I c
if self.vxlan_mode == lconst.VXLAN_MCAST:8 S3 i5 g- X* K1 r! ^ @" p
args['group'] = self.get_vxlan_group(segmentation_id)+ q5 O* c5 G1 D9 b) P( I, Y
if cfg.CONF.VXLAN.ttl:
2 N) ~" m# B9 e" v) \ args['ttl'] = cfg.CONF.VXLAN.ttl5 H4 Q A- \; b' P* d" Z, A- F, f
if cfg.CONF.VXLAN.tos:4 }7 m! _: q7 l4 v
args['tos'] = cfg.CONF.VXLAN.tos& n2 C, w4 _* D$ i9 d$ j
if cfg.CONF.VXLAN.l2_population:
- {1 F/ C2 P [3 n% @ args['proxy'] = cfg.CONF.VXLAN.arp_responder
# r& B- ?0 P# r( x: i try:
, U" t# B" ]; m int_vxlan = self.ip.add_vxlan(interface, segmentation_id,
# Z) [& |" q5 f- L **args)
A! _/ `- c+ ]* d- g7 v/ L! w" @1 j* y ) Z1 d! p) \1 d
(8). 将 tap 设备加入到 linux bridge 中2 p- n# Q! |% D# {
bridge_lib.BridgeDevice(bridge_name).addif(tap_device_name)
, ~( _. c& ^ V9 i(9). 如果将一个 tap 设备被删除,那么 linux-bridge-agent 会发现:
' p) ]7 Y$ E H3 r2016-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'])* \1 q X7 R/ R$ O% S0 R
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" L" c1 A) }* B& V/ ?- _
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.0 C9 l$ c5 c2 b0 r9 Y( i2 B5 o
3. 关于上述工作过程的简单结论" x C* }/ ^; p! J3 q
3.1 简单结论) ], K- o' _( c& L9 w5 |) h
1. l3agent 和 dhcpagent 创建 network namespace 时创建 tap 设备,和 network namespace 中的 interface 是一对 veth pair。当手工删除 tap 设备时,相应的 veth endpoint 也会被删除。+ x0 L' E E& \1 O
2. linuxbridgeagent 不断扫描服务器端和本地的 tap 设备
* Y5 f/ c- Z `% q/ f3. linuxbridgeagent 获取需要增加和修改的tap设备列表
/ D9 H- y5 o( @: ^+ h6 J, U4. 对于需要增加的 tap 设备,获取其详细信息,主要是 network_id,network_type,physical_network,segmentation_id,device_owner 等,然后根据这些信息,创建 linux bridge,并加入所需要的 interface' i" @6 X2 Z+ z% q, \! U# d) w1 n
5. 创建所需要的 linux bridge,并将 physical interface (provider network 的 physical interface 或者 tenant network 的 vxlan interface)加入 bridge,并且将 tap 设备也加入该 bridge6 K8 l! {% V8 N b' X
6. 如果发现某个 linux bridge 没有创建出来,首先需要查看有没有相应的 tap 设备存在;如果 tap 设备不存在,则查看相应的 qdhcp 或者 qrouter 中时候有interface! j/ z7 S7 K( Q
1 Q* {! t ?. q! y" X具有多个 VLAN 租户网络时候的网络元素示意图:
; n0 R' l: k8 s- ~: n
7 T6 Q: }' H: N# L# Z) H & e1 o O0 Y/ M! ^ B9 Z
4 }8 a. h9 W, L9 y) P! m
$ V/ a. h# m# e, l4 [/ c
3.2 关于 unnumber interface
& i4 m. I% g: \" Q$ d1 I- fOpenStack 官方的 host networking 配置中,连接外网的 interface 可以是 unnumbered 的,从字面意思理解,就是该 interface 上不需要配置 IP 地址。$ F7 J. {, \8 I+ L: w% C7 `. ~
6 U! `+ T+ ?/ R& {) X2 Y1 [2 U配置的时候,修改 /etc/network/interfaces:( a( L' M+ q: L j0 x0 X3 }
# The provider network interface& w7 O: A' o4 O- S
auto ens224
+ y, J% x$ w6 {% m+ tiface ens224 inet manual
7 }. r9 _7 Y* Z4 Aup ip link set dev $IFACE up$ x7 U$ _, E W z8 ?
down ip link set dev $IFACE down
! Z8 R# c! a* a% j/ X8 R9 S配置好以后:; b. A# h1 M4 g, t3 {% I9 l6 a
5 R# v. M. N; @. u3 `# K i. m
root@controller:/home/sammy# ifconfig ens2247 S5 I$ O% g! N, v/ |" A3 z% ~
ens224 Link encap:Ethernet HWaddr 00:50:56:9c:4d:94, S& E) O- ]( r
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
3 P1 i2 s( V' ~7 v RX packets:27300737 errors:0 dropped:0 overruns:0 frame:01 D) M: n* g( |# O" P( t, _
TX packets:61547 errors:0 dropped:0 overruns:0 carrier:0
0 T: D( P! R$ }7 y+ d- E) u, A& @9 k collisions:0 txqueuelen:1000$ F( m4 D8 h+ Y0 `) v
RX bytes:31951077598 (31.9 GB) TX bytes:5966060 (5.9 MB)
; m7 B4 n0 F, v
4 k r) u) X; `- F6 h9 ~( ^root@controller:/home/sammy# ifconfig brq96609bfa-0e
" A1 N9 I' e/ K8 {1 M8 d% zbrq96609bfa-0e Link encap:Ethernet HWaddr 00:50:56:9c:4d:94
- M$ H ^/ R( \/ f9 a3 [ UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
4 Z5 P& H9 |5 E6 \# B RX packets:32855 errors:0 dropped:0 overruns:0 frame:0/ u* w% n I' G5 S i
TX packets:2 errors:0 dropped:0 overruns:0 carrier:0
) B# a6 v, \ J6 v8 P9 f collisions:0 txqueuelen:1000% I" x' }2 c3 ~7 H
RX bytes:2731030 (2.7 MB) TX bytes:84 (84.0 B)' | x# u0 H0 n7 S" l, L- N; z; u
& n! P5 H. A- ]8 e( q; B" D. [8 m
具体原理不详,但是应该是因为 qrouter 的 qg network interface 和物理网络中的路由器的网卡之间是网络二层,因此中间的设备都是属于二层的,因此不需要处于网络三层的 IP 地址。
6 Y- M1 \3 i" e& b& C4. 使用 linux bridge 时的拓扑结构
' A' y( ^: Q. f3 ] h# z7 g& P2 ^8 b4.1 网络节点上/ E) L/ [- B; ?0 e, @( i2 j# R
为了更清楚,我们来对比着看 linux bridge 和 ovs 的两种方案:
- s+ }1 ]+ T) c; W+ hlinux 方案:
9 `; H4 ?! B) z* Z+ ]9 f# ] d * U; p8 B4 ^; q/ s: v
网络服务:! J* G! A* J, n* I" G- d7 g
• Linux bridge agent3 t# K( j& X: J0 z$ ]2 ]7 I
• L3 agent
3 g! C D1 {1 `2 K0 O• DHCP agent
: E" g$ F1 o/ c% y• Metadata agent
6 v1 w& M3 p' v9 n5 RLinux bridge agent 会为每个 VLAN 虚拟网络创建一个 VLAN Bridge,它连接多个网元:
( p+ ?: }3 V' |' c- q1 p" A• VLAN 子接口,从物理网卡(图中的 interface3)上创建,每个子接口对应一个VLAN ID,其名称格式为 device.sid,其中 device 是物理网卡名字比如 eth0,sid 是 vlan id。
& j, ^5 F% p) I: M+ [, E- m0 q7 h• 连接虚拟机的 tap 接口
7 C0 _( O0 W/ Z• 和 qrouter 连接的 tap 接口
! m6 e9 M, m8 B! ^+ u$ C• 和该网络的 qdhcp 连接的 tap 接口
: E E5 y& F3 K( r& _如果同时有 VXLAN 虚拟网络的话(linux-bridge 不支持GRE 隧道模式),会为每个 VLAN 虚拟网络创建一个 Tunnel bridge。它连接多个网元:; n% T! J# _2 d: Z% i: N
• vxlan interface,这种接口每个虚拟网络一个,名字格式为 vxlan-sid,其中 sid 是分段ID。
4 i9 x$ A4 P. P; N& V" Q2 B• 连接虚拟机的 tap 接口
! @( |1 J2 n( d. @6 o% I• 和 qrouter 连接的 tap 接口
" j# M" Y" r8 z& b+ _• 和该网络的 qdhcp 连接的 tap 接口: @" ~% X, P% t3 `$ V0 r
安全组规则在 tunnel bridge 和 vlan bridge 上。2 Z# ^6 ]( f/ K9 \9 f# b
OVS 方案:
" ?/ a4 J8 {$ c7 y! I. V# A" K( o
- a, G7 s" h3 `' b$ ~这里面,br-int 会负责加本地 VLAN 标签,br-tun 会负责将 VLAN ID 转换为 VXLAN ID。! y: w+ ^8 S$ @6 ^5 ?
1 _: i5 `5 [- p4.2 计算节点上
/ d3 R2 Q y* X4 S/ I8 M0 \同样来对比着看。+ C2 F" U7 P+ x: r2 q( Y% b$ ?
linux bridge:
1 R4 f) F" S. @- I5 `
+ G) i# X( X8 t网络服务:2 v' F. ]; @ M1 Q
• Linux bridge agent. Y* P/ r& O' F5 b5 k" W
和网络节点类似,只不过没有 qrouter 和 qdhcp,不在赘述。, P- M8 Y; B. O. ^. S
OVS:6 q/ D! c9 s$ z2 ~5 @. g; Q3 F
9 ?, p* ~ p' O7 g7 J' j* P+ j
W$ d1 v* A# B7 E0 qOVS 放在在 br-int 上实现 VLAN 标签,在 br-tun 上实现隧道,在 qbr linux bridge 上实现安全组。
# J8 w% c4 c' }$ r: }9 a: ? , F7 j' P8 z1 G0 A& F% U
4.3 网络路径 - 南北向网络流向
7 B) x8 D6 J5 F$ l* K / h9 w4 \5 k4 T* n6 L0 V
VLAN 网络和VXLAN 网络井水不犯河水。这图上的配置中,计算节点和网络节点上的物理网卡都分开了。
, f) [* k# U( U' F2 f& I- q( b! s, y4.4 网络路径 - 东西向(不同网络)
/ E2 [6 k8 Y7 u3 i$ U1 k5 ` 8 Z) r2 ^4 J# w' c+ O5 \
4.5 网络路径 - 东西向(同一个网络)
+ C! \- C( B; _3 O 5 I6 C. y; L4 i8 `9 K& X2 z# ^' W; W. D
2 i8 G/ [. C0 C, M' d+ r请详细说明和配置,请参阅参考文档。0 ]( U2 s' `9 |
5. 一点结论
) S9 ~7 Y* e7 k. y0 x6 \, A( R7 `3 N和基于 OVS 的二层网络相比,
& m% ^" h5 C. b. c• 功能和架构上:基于 linux bridge 的实现还是有一些短处,比如每个虚拟网络就需要一个网桥,这在大规模环境中会带领资源使用和管理上的问题。其好处是本身架构比较清晰。% [2 U, T2 `/ J) |, [! p
• 性能上:基本上差不多,如下图所示,不管是 vxlan 还是 vlan。! e; L9 ^, f, b1 ^+ X
7 r/ p& n5 m0 s
5 Q; ]2 u# @0 w4 b' _& [8 P |
|