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

楼主 |
发表于 2019-10-25 11:23:29
|
显示全部楼层
虽然大部分的OpenStack 部署环境中,都会使用 Open vSwitch 来作为虚拟交换机来实现二层网络功能,但是Neutron 仍然支持使用 Linux bridge 作为虚拟交换机来实现二层网络。本文就此做些分析和说明。 : L: _1 h0 E4 q7 b0 X$ R2 l
同时要指出的是,OpenStack 官方已经把 linux bridge 实现标记为 legacy 的了,文档从 2016 年后也没怎么更新了。这是因为,linux bridge 和 OVS 相比,只支持基本的网络功能即二层交换,但不支持VLAN 标签和隧道。因此,linux bridge agent 利用linux 内核功能(VLAN 子接口和 VXLAN 接口)来实现VLAN 标签和隧道。
6 s/ f) s* l, S' W
8 H |1 g9 {& N$ u9 \' S, u6 O 1. 测试环境
r8 R3 c# s4 ?2 w. @0 a以下面的环境为例(网络节点上):
n0 r) ]4 D6 K(1)linux bridge
$ F7 H# }& b; j1 v* W
! Q, O+ u* p2 J1 nroot@controller:/home/sammy# brctl show1 B' d# E; k/ B: ?
bridge name bridge id STP enabled interfaces8 P6 z4 a7 W, W# Q; t
brq85925305-b4 8000.563534c8d02d no tap0bb8efeb-10
1 S: b5 G+ ]" Y3 B+ N1 i" E( } tap798c87d1-a2
2 A7 g) ~! e4 D- K" ~ vxlan-25! ^/ U; A' s* [6 [- K' S
brq96609bfa-0e 8000.0050569c4d94 no ens224
: S/ B2 E* h0 Z/ f" Z* T6 b+ M V( m tap60dbdc2f-a0
( {% [" m2 O. _brq971ffda2-e5 8000.a6acb08e4fd6 no tapb1eaae00-e5$ S* j- ~' Q* Z u$ \3 g% C
tapf70543dd-0f
$ x- j! d. y/ v( {* B3 Y vxlan-10
+ k* M' b3 D( S) E" B' C. C
- [( T7 R+ g+ \! U, o6 c ~(2)OpenStack 网络和 network namespace:
8 T% ~/ |- _; n# g6 |, ? * w2 T2 \5 z1 v! w
root@controller:/home/sammy# neutron net-list
" g9 z2 x8 j" W ~& C. P! S+--------------------------------------+---------+-----------------------------------------------------+
6 M3 L1 K! b5 w* x" z* r+ w| id | name | subnets |( t& {5 Z" ~9 i1 `' B' i. n
+--------------------------------------+---------+-----------------------------------------------------+
$ l* v7 Y$ S& S- i' K& G| 96609bfa-0e22-4bb7-8dba-6ef532ea6076 | extnet | afa7d205-3026-439f-aca7-295a9f9b2a71 10.62.227.0/24 |4 T1 E; r' B3 L+ P
| 971ffda2-e567-40a0-a2c8-b31a577fd4d3 | appnet | 4c68eacb-bf3e-408a-a941-94e93eddb22b 11.0.0.0/24 |
. r! y8 C9 L- K3 x4 U| | | 3d596991-de8f-4ae4-8913-89426a8abbd7 10.0.0.0/24 |# [; r$ L- V7 d* B& E5 \1 D/ x
| 85925305-b477-4cc6-9654-67d9bf1e7cd8 | appnet2 | 4575c7f1-7f08-4917-9904-ec65af38619b 20.0.0.0/24 |
7 Z! w' b9 t B+--------------------------------------+---------+-----------------------------------------------------+
/ T5 I1 R' X' M, _8 C! j5 y) uroot@controller:/home/sammy# ip netns! i1 r$ _* A i" W+ d/ }# g
qdhcp-85925305-b477-4cc6-9654-67d9bf1e7cd8 (id: 2)
- N+ M+ k# H+ _) _3 xqdhcp-971ffda2-e567-40a0-a2c8-b31a577fd4d3 (id: 1). b1 L' c! G6 u; p
qrouter-39a77439-8a28-49c1-bf97-ac931510631b (id: 0)- T- v" ~2 F d! N! y
8 S7 L) l1 Q8 @. f4 N i) q4 ](3)示意图:8 d8 E& P7 j' Z
0 z* Z/ g# u. f
(4)说明:
8 b5 {! h+ b3 e) k2 f• qdhcp 和 qrouter 都是 linux network namespace 实例
3 K# R0 Q+ L/ V8 \7 S4 y7 u! \• qdhcp network namespace 的数量等于启用了 DHCP 的 Neutron network 的数量。' T6 V) T0 c/ p# |: A1 H
o 当一个 network 中存在至少一个 subnet 启用了 DHCP 之后,会有一个 qdhcp network namespace 被创建出来;2 a1 a! b) w, H+ Q- q- ^
o 当一个 network 中多个 subnet 启用了 DHCP 时,它们共用一个 qdhcp,以及 dnsmasq。
% e( x$ E/ H+ p4 wo 其 name 使用 network id,比如 qdhcp-85925305-b477-4cc6-9654-67d9bf1e7cd8
9 k- H s% S) q, o8 N• qrouter network namespace 的数目等于 router 的数目,也就是说,系统中一共有几个 router,那么就存在几个 qrouter network namespace' h' {! D: z# F) s9 r& N& O
• brq linux bridge 的数目等于 neutron network 的数目,其 name 是 network id 的前几位,比如 brq96609bfa-0e' E% o% H. m z
• 一个 network 的 qdhcp network namespace 和其 brq linux bridge 一定有连接5 A+ `: G& e5 |7 i/ C5 l4 z( r
• qrouter 之内的 network interface 分两种,一种是 qr 开头的,每个连接到 router 之上的 subnet 都有一个;还有一个是 qg,每个连接到 router 的 external subnetwork 有一个
! S! C3 j; E9 h4 K• qrouter 的每个 network interface 都通过 veth 连接到所在网络的 qbr linux bridge 上# p6 c, h: x7 m3 B: X. h! R: `
• qbr linux bridge 连连接两种物理设备,一种是 vxlan interface,每个 tenant network 有一个,另一种是在 physical network 对应的物理网卡上创建的子接口(sub-interface)% }6 g O& n. r- T5 E
• 对于 physical network 的 qbr 来说,用户可以指定它,并且在linuxbridge_agent.ini 中通过 bridge_mappings = List of <physical_network>:<physical_bridge> 进行配置;也可以不指定,此时 agent 会创建它。当同时配置了 physical bridge 和 physical interface 时,前者优先。
& C0 @1 G, ?' W+ I如果 external network 中有多个 subnet 的话:
3 e; t% F" {* @1 L& {7 x; M(1)每个 qrouter 只允许有一个 External Gateway,也就是说它只有一个 qg network interface。当 external network 添加多个 subnet 之后,只有第一个被当作 external subnet,其余的都会被当作 internal subnet。
( S* Y3 s( {8 _# R& ?5 Q(2)在 qrouter 的路由表之中,2 e7 A# S7 R4 ]8 }' f; v1 K" ]2 U
1 y5 O% I. \ g9 \4 t# C2 w. T
root@controller:/home/sammy# ip netns exec qrouter-39a77439-8a28-49c1-bf97-ac931510631b route
" ~5 E9 B: |* n6 z8 MKernel IP routing table
& t" c' a; d$ sDestination Gateway Genmask Flags Metric Ref Use Iface
4 I9 m% w i6 `2 ddefault 10.62.227.1 0.0.0.0 UG 0 0 0 qg-e09fce07-cd5 v" t. c8 X }/ c
10.0.0.0 * 255.255.255.0 U 0 0 0 qr-b1eaae00-e5
0 c- }( A5 f4 ]2 b- l# ~. L0 x! p10.62.227.0 * 255.255.255.0 U 0 0 0 qg-e09fce07-cd
! o0 d4 @; {/ z7 U: D& h10.62.228.0 * 255.255.255.0 U 0 0 0 qg-e09fce07-cd) {6 a% X' i+ o/ \1 O" _
10.62.228.0 * 255.255.255.0 U 0 0 0 qr-124ff148-b76 E- T2 Y% s' r
11.0.0.0 * 255.255.255.0 U 0 0 0 qr-16d9b0cc-38& V% _/ r0 z# r/ {2 {
20.0.0.0 * 255.255.255.0 U 0 0 0 qr-0bb8efeb-10: ~; w- [5 @5 D% t
; J+ D5 H$ j" Y% v, ^- d% p
$ s8 t0 S' D; I' ]; `; J2. linux-bridge-agent 工作过程分析
) \* c5 j- L0 N. a- d8 k(1)linuxbridge-agent 会启动一个循环,不断扫描上面红框中的 tap 设备9 E0 F4 i! T- Y5 ]. t' M
) e: L' w" X! E' t- x0 e" {2 W def daemon_loop(self):
: G1 P: ^7 A' M' T! n...+ K; _( t0 ]9 a) C! h( u
while True:
9 d P0 n1 F' r2 d% [' F, X start = time.time()
# w% J7 @# N* T: P) A. ..- E2 p1 j. q. o, j9 o
+ _& i$ L0 V0 z" J/ E
device_info = self.scan_devices(previous=device_info, sync=sync)
! B! z) `) f4 I$ S4 U5 | sync = False
* l7 y: A: ?" Y* K" ~3 n1 \2 M' c
0 m9 V) h2 K5 H; D' [ if (self._device_info_has_changes(device_info)
Y* q% L( u; W& O8 a or self.sg_agent.firewall_refresh_needed()):/ L& V2 C# f* N7 B# j3 p) S
LOG.debug("Agent loop found changes! %s", device_info)) I# ]! Y: F$ u( D9 Q
try:. G+ p5 Y) r5 @( y, ^ \3 x
sync = self.process_network_devices(device_info)8 n" D+ B4 }: c( U, s$ }
except Exception:$ O9 F9 \; L& |* h
LOG.exception(_LE("Error in agent loop. Devices info: %s"),' S/ K9 b4 _# O4 f3 v! o
device_info)7 K' P: y, n" B3 K& u+ `
sync = True
* ^$ d; a' C; b# j% k
9 D% |, Q& ?0 s( p I& j$ {这是它首先找到的 devices:
+ H3 r1 c2 o1 Q" u(Pdb) p bridge_lib.get_bridge_names()
0 \+ K- m+ v6 F4 B9 p2 R A['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']* {/ o( p9 V! j+ }6 W
然后过滤出 tap 设备:9 o0 u0 W. [1 Z+ F
get_all_devices()->set(['tap0bb8efeb-10', 'tap60dbdc2f-a0', 'tap795e6e86-94', 'tap798c87d1-a2', 'tapb1eaae00-e5', 'tapf70543dd-0f'])
X+ j: U6 k$ G/ ?2 D(2)根据 previous 中保存的历史数据,再接合服务器端和本地更新时间,计算出需要更新的tap设备列表:; U, Q7 x7 M: k9 d8 _
{'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([])}
5 W1 `+ D0 Y; |! H: u- _# @ (3) 通过 RPC 获取 tap 设备的详细信息
% l* k2 K; h0 M; C
( G+ W+ [& [, @5 `: ?- F7 R9 t# Z(Pdb) p devices; p- m# L4 ~/ q( o' [1 K/ R
set(['tapf70543dd-0f', 'tap60dbdc2f-a0', 'tapb1eaae00-e5', 'tap795e6e86-94', 'tap798c87d1-a2', 'tap0bb8efeb-10'])1 n/ U& }3 e" ^6 y
2 }' D& s! X8 T3 \
5 c7 b' }% p5 V2 Udevices_details_list = self.plugin_rpc.get_devices_details_list
, Q5 j+ M* |' b# g5 r, W8 x% f7 R9 k3 D
(Pdb) p devices_details_list
' I% I9 N7 N3 H[{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': []}]/ {5 T0 @' q) ~& b- B
7 U' z/ U6 z+ U' d) [1 Z, U0 o' U( p
(4) 对需要处理的设备,调用 self.process_network_devices(device_info) 函数进行处理
+ F' H. q* o4 s+ e. }(5). 调用 plug_interface
! r1 M- S$ k# N# l+ |- z/ X% cinterface_plugged = self.mgr.plug_interface(network_id, segment,device, device_details['device_owner'])
5 `2 x( G0 Q0 p% d, }(6). 需要的话,使用已经配置的或者新建 linux brige,并将 physical interface 设备加入其中2 ~) w* n) e: D+ M( D
bridge_name = self.get_existing_bridge_name(physical_network) #获取为 physical network 配置的 linux bridge
6 O6 j' C# v4 Tbridge_name = self.get_bridge_name(network_id) #或者根据 network id 生成 bridge name
+ c: k: \9 L" _, ` s(7).根据不同的网络类型,分别处理 vxlan bridge,flat bridge 和 vlan bridge
$ \ P/ D N' F
3 a& f/ V) ]4 F8 p def ensure_physical_in_bridge(self, network_id,
7 D% y+ {' B: R9 P network_type,
; K4 O; [6 M; o ?: V. D physical_network,
, @9 T+ ^( K h) R- l8 m( L9 U7 a3 N segmentation_id):, I" a; o1 P0 s+ y
if network_type == p_const.TYPE_VXLAN:$ b, d3 P# J3 E& S
if self.vxlan_mode == lconst.VXLAN_NONE:
$ y k7 P: H) @+ J7 p" B LOG.error(_LE("Unable to add vxlan interface for network %s"),5 Q% Z# u2 f9 a V1 h
network_id)/ Z4 w3 b" i! O# S& ^2 n! z
return
8 {- M; N, T8 C& `+ | return self.ensure_vxlan_bridge(network_id, segmentation_id)
- }! _& ? T& n6 U$ @ V& O: A: W; x; }4 A) _
# NOTE(nick-ma-z): Obtain mappings of physical bridge and interfaces& C5 Y2 }4 e; f# G) M0 M3 A. J
physical_bridge = self.get_existing_bridge_name(physical_network)
" M& R5 p# i, o+ P physical_interface = self.interface_mappings.get(physical_network)
" @* j" W0 D% U$ Y if not physical_bridge and not physical_interface:
! {9 y6 t$ H( M LOG.error(_LE("No bridge or interface mappings"
. [& O% o8 ?3 b# }/ ^# P " for physical network %s"),
! b) \- Y1 i& `+ Q( J physical_network)
5 M& ^# ` D) K- b4 v. ~ return
, @& @+ C) @, v$ r6 X if network_type == p_const.TYPE_FLAT:
4 |9 ?, ?/ W8 _( K7 {" M! U return self.ensure_flat_bridge(network_id, physical_bridge,
5 }, s' j/ A: T7 ^# j, I physical_interface)* |) u. g! a# C7 F, Q8 s$ D
elif network_type == p_const.TYPE_VLAN:$ r0 Y0 }# U a8 @ c
return self.ensure_vlan_bridge(network_id, physical_bridge,
' b+ a) U$ }. H: e8 X physical_interface,
2 @+ R$ H( D4 i1 N. Z& e, e segmentation_id), A, r9 f8 y0 _( Q- N
0 L6 p+ I$ O& w! i对于 flat 类型的网络,调用 ensure_physical_in_bridge5 l" u" H; d# ~" i3 k
def ensure_physical_in_bridge(self, network_id,network_type,physical_network,segmentation_id)
& g! R* Y9 i% ]0 V if network_type == p_const.TYPE_FLAT:7 O. [5 e( m1 K! D* J( j
return self.ensure_flat_bridge(network_id, physical_bridge,physical_interface)- f8 y! t3 o3 z+ m
如果有配置 physical bridge 的话,使用它;否则创建 bridge,并将物理网卡配置的 ip 地址和 gateway 从网卡挪到 linux bridge' n* q0 g, I4 d5 l* P' E( ~! Q! s
; Q5 n9 c6 Q( o( l' n/ x% q& d* R
def ensure_flat_bridge(self, network_id, phy_bridge_name,physical_interface):
5 l% S$ K0 a( i M0 S) B """Create a non-vlan bridge unless it already exists."""
5 q1 ] C3 U' [! w% l8 d if phy_bridge_name:
# `: W' z) I: N/ [/ x) D4 l# ] W/ J. N return self.ensure_bridge(phy_bridge_name) #获取预先配置好的 linux bridge
5 s0 D$ g) o9 h8 X3 s4 T else:
+ T' J: N6 s! c+ g' A+ M& [ bridge_name = self.get_bridge_name(network_id)- Q+ }. m! m2 t& y v M' ~1 }
ips, gateway = self.get_interface_details(physical_interface)' g/ P, k/ O( w
if self.ensure_bridge(bridge_name, physical_interface, ips,gateway): #创建 bridge. W9 E" n% i6 Q. o& g' `% P
return physical_interface
2 ~, L, K# ]2 G6 ^3 c . H0 o6 Y0 f9 r. s4 `
对于 vxlan 类型的 network,需要创建 vxlan interface
$ v+ x! f+ |0 ^4 m I
" g$ ?+ H( B+ r/ v8 h: W def ensure_vxlan_bridge(self, network_id, segmentation_id):
* `* W _' |$ ~5 g! d0 F """Create a vxlan and bridge unless they already exist."""
3 D. W9 R( _6 y6 ?: A! w interface = self.ensure_vxlan(segmentation_id)
1 i& o6 g% B1 @1 ~/ P, u if not interface:
% M# ^+ m- R; F% n+ L0 Z# F LOG.error(_LE("Failed creating vxlan interface for "
. e" X. q1 U- _0 o# D( u+ X( J "%(segmentation_id)s"),
- ^6 h7 M3 c2 a$ c {segmentation_id: segmentation_id})
3 w0 I2 R% ]; ? return
% y6 }) v4 k/ e# X4 }+ ` bridge_name = self.get_bridge_name(network_id)
) b% z4 b" H& ~) k; o: g# ] self.ensure_bridge(bridge_name, interface)
1 K' k' M' |2 G1 ^! Z/ _% J/ f( K2 Y return interface
5 y9 }- L& g, P& \. @+ M( J$ K , y3 m2 F/ z- c R$ X4 c7 \
创建 vxlan interface:" S' q4 R. T7 E0 ~
- r; o- c9 B. s1 ^. t" i8 V0 f def ensure_vxlan(self, segmentation_id):
1 ]0 K( e+ h4 }+ o2 P! o& A; C """Create a vxlan unless it already exists."""0 Z- y* e9 ?& U. [
interface = self.get_vxlan_device_name(segmentation_id)
! A! X. H! _* P5 h! A5 q if not ip_lib.device_exists(interface):
; k2 t4 N7 C. D9 B$ v! {$ [4 g LOG.debug("Creating vxlan interface %(interface)s for "
' m6 m3 {* U1 f1 G "VNI %(segmentation_id)s",0 N$ G! ^9 |2 v2 z& }0 K
{'interface': interface,
& F! {) Q9 ^9 Q+ y 'segmentation_id': segmentation_id})
" J# m" m* c+ p. D. w9 f args = {'dev': self.local_int}
+ A7 `0 h, A' i. U8 W3 M$ G if self.vxlan_mode == lconst.VXLAN_MCAST:
) y0 t9 C, U5 W7 f args['group'] = self.get_vxlan_group(segmentation_id)
- E5 l; d0 S) y if cfg.CONF.VXLAN.ttl:
$ Y0 B7 N' U) T" q8 j. O! W: u1 X/ G: Q4 P args['ttl'] = cfg.CONF.VXLAN.ttl" |" g. k5 ^9 Y0 J
if cfg.CONF.VXLAN.tos:
$ P" e [; u; E args['tos'] = cfg.CONF.VXLAN.tos0 Z' S& M5 Z* U5 K& k6 u7 @
if cfg.CONF.VXLAN.l2_population:
8 G4 `" a# s6 I5 Q args['proxy'] = cfg.CONF.VXLAN.arp_responder3 Y- _% o% V# k4 p) T/ |
try:, Z% b; f l7 d6 l' r n2 x
int_vxlan = self.ip.add_vxlan(interface, segmentation_id,
4 E/ J$ M" A5 G& y- ?6 q* x* T **args)
1 g, W( p' H% U5 W3 R% q, ^2 ^ 4 Q5 u4 x _7 N6 E- N P* i/ `: r- p
(8). 将 tap 设备加入到 linux bridge 中0 X6 b8 X) B2 n% x, F- Y5 z5 O
bridge_lib.BridgeDevice(bridge_name).addif(tap_device_name)
8 A$ y+ T l" ~/ Q(9). 如果将一个 tap 设备被删除,那么 linux-bridge-agent 会发现:! D3 {9 w; e1 _) N j
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'])
( ` @6 b$ I9 U! O2016-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
: k) }- e/ q% Z2016-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.* v" F% N' W5 ], w
3. 关于上述工作过程的简单结论$ A! z6 R$ f d
3.1 简单结论
0 ]- L) s2 ]) s( V# |+ |1. l3agent 和 dhcpagent 创建 network namespace 时创建 tap 设备,和 network namespace 中的 interface 是一对 veth pair。当手工删除 tap 设备时,相应的 veth endpoint 也会被删除。6 P% G V/ S) w" O
2. linuxbridgeagent 不断扫描服务器端和本地的 tap 设备+ v; t% s* m& d0 v
3. linuxbridgeagent 获取需要增加和修改的tap设备列表
' c1 s# Z9 y$ J6 ^- G4. 对于需要增加的 tap 设备,获取其详细信息,主要是 network_id,network_type,physical_network,segmentation_id,device_owner 等,然后根据这些信息,创建 linux bridge,并加入所需要的 interface2 p7 C" T4 i( S/ u: V* a
5. 创建所需要的 linux bridge,并将 physical interface (provider network 的 physical interface 或者 tenant network 的 vxlan interface)加入 bridge,并且将 tap 设备也加入该 bridge
: `7 I4 w. A, ~' D5 @* m) |$ F6. 如果发现某个 linux bridge 没有创建出来,首先需要查看有没有相应的 tap 设备存在;如果 tap 设备不存在,则查看相应的 qdhcp 或者 qrouter 中时候有interface
+ b/ U U* A; }) |' V( j a2 j5 Q$ U/ S0 n! l* T
具有多个 VLAN 租户网络时候的网络元素示意图:% H! U' t% J* u: l. S
, U# X- Z/ ~- ]1 t% |0 ~; r
+ G$ A& _" I& g1 p+ F / `% C) r" @1 u& y
' ~' a. d: h V- L
3.2 关于 unnumber interface
% t' [8 T, k+ E# \- I8 ?& s" S) V4 P5 sOpenStack 官方的 host networking 配置中,连接外网的 interface 可以是 unnumbered 的,从字面意思理解,就是该 interface 上不需要配置 IP 地址。
' a) F& V \" a * t$ @9 o- m# G& l# S1 e
配置的时候,修改 /etc/network/interfaces:
6 @, O5 g/ X, y1 L+ r" m1 a) B( D; E- l# The provider network interface. Z- ?, [& `: H4 w$ E: {
auto ens224' `# O- w* a* e( u( v
iface ens224 inet manual
, i* T8 a* f+ i5 Aup ip link set dev $IFACE up/ S4 @. H3 C3 E+ h
down ip link set dev $IFACE down
+ ?) ^8 i! |+ |4 R配置好以后:
0 _+ }" q0 @3 C8 M" ]
. ?5 w2 Q$ x; V1 kroot@controller:/home/sammy# ifconfig ens224! Q9 s$ T" `6 p# v+ F# W
ens224 Link encap:Ethernet HWaddr 00:50:56:9c:4d:944 d* j! I$ `: C1 Z# l' ? s
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:14 @6 p2 Y% I: n; |* O+ w
RX packets:27300737 errors:0 dropped:0 overruns:0 frame:0
. j C3 C. n# S5 y TX packets:61547 errors:0 dropped:0 overruns:0 carrier:0
% U q$ ~$ \' b. @8 q6 D9 ^9 K collisions:0 txqueuelen:10002 h2 r: _* s0 p* h
RX bytes:31951077598 (31.9 GB) TX bytes:5966060 (5.9 MB)* _) V/ T. V4 Y+ g. U' H) ^) y0 m
6 d. g* P/ u6 \ ^
root@controller:/home/sammy# ifconfig brq96609bfa-0e' H+ G7 Z5 A- i, t# b% x
brq96609bfa-0e Link encap:Ethernet HWaddr 00:50:56:9c:4d:94
2 n- Q. p0 X( v% I$ }2 L4 Q4 o; Q UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1/ |+ S' l& P! ?6 l% ?! ]3 K
RX packets:32855 errors:0 dropped:0 overruns:0 frame:0
) G( w7 l. }& M. R1 V/ g TX packets:2 errors:0 dropped:0 overruns:0 carrier:0+ Y& A( |* d/ h: z6 I: M5 e
collisions:0 txqueuelen:10007 M( p+ g2 E c- Q
RX bytes:2731030 (2.7 MB) TX bytes:84 (84.0 B)$ t% {1 n2 B0 x K
1 ~: J- u i# Q" n
具体原理不详,但是应该是因为 qrouter 的 qg network interface 和物理网络中的路由器的网卡之间是网络二层,因此中间的设备都是属于二层的,因此不需要处于网络三层的 IP 地址。2 Z3 S# O7 S7 |* H
4. 使用 linux bridge 时的拓扑结构: p9 L; s, q& K
4.1 网络节点上% B: I3 Y, a& \9 H" e
为了更清楚,我们来对比着看 linux bridge 和 ovs 的两种方案:2 F' t/ }/ V& N# o8 g; f( c5 v. X4 `
linux 方案:+ R6 k! I1 t( u# L3 Q4 V( {
1 F$ d7 x% n) k$ X. l
网络服务:2 F% `& f$ b5 g- _ @( d# C
• Linux bridge agent
4 q/ d8 x9 O0 ^! m) P1 c+ \• L3 agent
# }# I1 r/ o$ k2 ?4 S J4 `+ a• DHCP agent; `2 p* p$ s3 G Z# o( S. I
• Metadata agent; d- Y% |/ S4 L) O7 z! S/ ~
Linux bridge agent 会为每个 VLAN 虚拟网络创建一个 VLAN Bridge,它连接多个网元:" B5 F) f: k6 F
• VLAN 子接口,从物理网卡(图中的 interface3)上创建,每个子接口对应一个VLAN ID,其名称格式为 device.sid,其中 device 是物理网卡名字比如 eth0,sid 是 vlan id。
% ?- y1 @4 b! n8 O, J• 连接虚拟机的 tap 接口. m! X) s7 u0 Y: K: C
• 和 qrouter 连接的 tap 接口
( r0 Z# K O6 u, w: h• 和该网络的 qdhcp 连接的 tap 接口2 W8 A. a1 v" \6 K7 ~5 P
如果同时有 VXLAN 虚拟网络的话(linux-bridge 不支持GRE 隧道模式),会为每个 VLAN 虚拟网络创建一个 Tunnel bridge。它连接多个网元:6 W, H/ ?+ o3 y$ c0 A& R [
• vxlan interface,这种接口每个虚拟网络一个,名字格式为 vxlan-sid,其中 sid 是分段ID。
8 n J. r. f& {4 H• 连接虚拟机的 tap 接口
. A' U' Z' n4 X/ r( l• 和 qrouter 连接的 tap 接口7 c, P1 E3 ~8 F
• 和该网络的 qdhcp 连接的 tap 接口
- E+ W( z J4 W/ m8 P安全组规则在 tunnel bridge 和 vlan bridge 上。/ T1 ?- F& Q0 ?2 _+ h' r
OVS 方案:. E8 V" I. X+ A% x" |
* r& e8 l+ s* D
这里面,br-int 会负责加本地 VLAN 标签,br-tun 会负责将 VLAN ID 转换为 VXLAN ID。5 h' _. e! ~$ j' `9 Y; H
. r4 M( _$ q) x4.2 计算节点上5 F% W3 C- j( q' ?
同样来对比着看。" `0 W6 w. T/ A( R- x( v* M
linux bridge:
/ w6 E# A, ]6 Y X) E W, a0 ~6 o% z
网络服务:* [! h& z' |. V
• Linux bridge agent
; y: M C* Y6 b$ _# s和网络节点类似,只不过没有 qrouter 和 qdhcp,不在赘述。4 b* r: o# \$ k8 t+ @
OVS:
0 k9 R2 G$ i# }/ `* t
3 q; E! X2 \5 l8 c- v& Q B
/ S* B5 r7 k/ j+ |# O# X) hOVS 放在在 br-int 上实现 VLAN 标签,在 br-tun 上实现隧道,在 qbr linux bridge 上实现安全组。
+ j: }2 U& a' D/ a
Y+ a# U. H5 u0 u4.3 网络路径 - 南北向网络流向0 M1 G$ `+ ?% f% D/ M D# ^4 [
: t5 f7 m% o, |
VLAN 网络和VXLAN 网络井水不犯河水。这图上的配置中,计算节点和网络节点上的物理网卡都分开了。
5 \; I6 ~" R: s/ p$ u4 T& t! b2 L4.4 网络路径 - 东西向(不同网络)
% i0 B/ z0 W+ G& L
1 ~) H: `+ b+ H- s& X9 ?4.5 网络路径 - 东西向(同一个网络)! z( E3 ^. e) ?; f
" Z$ R2 i4 N7 o+ @6 [
6 {1 D% {* H' v/ a3 M请详细说明和配置,请参阅参考文档。" u- T- i' V% L+ d! M0 u3 a
5. 一点结论- _% O: S& J$ X/ M" `
和基于 OVS 的二层网络相比,4 E( Q, L) r9 m# |0 L- z( [
• 功能和架构上:基于 linux bridge 的实现还是有一些短处,比如每个虚拟网络就需要一个网桥,这在大规模环境中会带领资源使用和管理上的问题。其好处是本身架构比较清晰。. ?$ M/ {% T3 c' f
• 性能上:基本上差不多,如下图所示,不管是 vxlan 还是 vlan。
+ |, z" p; n3 z0 S5 h/ R' N
4 [4 O6 ?( d! p2 z; H: f" S3 w
4 W4 b" o, }0 t* ]( k1 z |
|