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

楼主 |
发表于 2019-10-25 11:23:29
|
显示全部楼层
虽然大部分的OpenStack 部署环境中,都会使用 Open vSwitch 来作为虚拟交换机来实现二层网络功能,但是Neutron 仍然支持使用 Linux bridge 作为虚拟交换机来实现二层网络。本文就此做些分析和说明。
8 F# ^! n: k. {" C% V同时要指出的是,OpenStack 官方已经把 linux bridge 实现标记为 legacy 的了,文档从 2016 年后也没怎么更新了。这是因为,linux bridge 和 OVS 相比,只支持基本的网络功能即二层交换,但不支持VLAN 标签和隧道。因此,linux bridge agent 利用linux 内核功能(VLAN 子接口和 VXLAN 接口)来实现VLAN 标签和隧道。
( D' E, ]0 Q$ L* v7 X# Z
- r7 s7 {2 ]- {8 [ 1. 测试环境
0 G K6 J' @9 v# g以下面的环境为例(网络节点上):0 m; O/ [! x- ^: }3 b9 S1 G4 Y
(1)linux bridge. B1 ?+ v1 z( S4 k1 d
( d1 g8 m e6 O4 I2 b8 J
root@controller:/home/sammy# brctl show
' m( Y D8 X/ a* b7 j, rbridge name bridge id STP enabled interfaces
8 p4 f8 S5 m: K8 F7 C, M; m0 Wbrq85925305-b4 8000.563534c8d02d no tap0bb8efeb-10
. f5 S, h0 ^, c. s tap798c87d1-a2
7 V4 w& P) Q+ q5 k4 P& h vxlan-25
6 D4 @ Z4 D5 c1 Q% I+ hbrq96609bfa-0e 8000.0050569c4d94 no ens224
8 F' B2 n3 A. v# }& C6 e/ {2 p& q tap60dbdc2f-a0
7 \$ g8 \: _# V5 W" s }brq971ffda2-e5 8000.a6acb08e4fd6 no tapb1eaae00-e5
& V) ]) ~" `3 T$ f( v tapf70543dd-0f
8 L# T+ P; J0 q vxlan-10
. Y( s6 J; P2 ]8 i
g9 a) r' I5 f; T(2)OpenStack 网络和 network namespace:* X/ M2 F" _% F" V7 K/ V; p
2 g a- ?8 L; @ n6 Yroot@controller:/home/sammy# neutron net-list- R3 r k# p& h+ u6 k [
+--------------------------------------+---------+-----------------------------------------------------+/ u& T1 P; e$ K6 P5 Q5 Z
| id | name | subnets |; n1 l/ e% Y2 I' b3 s1 w& f
+--------------------------------------+---------+-----------------------------------------------------+ w2 O/ Q, y+ l/ X
| 96609bfa-0e22-4bb7-8dba-6ef532ea6076 | extnet | afa7d205-3026-439f-aca7-295a9f9b2a71 10.62.227.0/24 |
* h; G' o- O& r r) _) T4 ^| 971ffda2-e567-40a0-a2c8-b31a577fd4d3 | appnet | 4c68eacb-bf3e-408a-a941-94e93eddb22b 11.0.0.0/24 |4 f8 C, w b) O6 e
| | | 3d596991-de8f-4ae4-8913-89426a8abbd7 10.0.0.0/24 |
A8 h3 G' l5 `# J; ~8 z2 i| 85925305-b477-4cc6-9654-67d9bf1e7cd8 | appnet2 | 4575c7f1-7f08-4917-9904-ec65af38619b 20.0.0.0/24 |7 Y5 X, `% E. o, p$ b) q7 D
+--------------------------------------+---------+-----------------------------------------------------+/ z/ D# {' B W
root@controller:/home/sammy# ip netns4 ] q( ?8 q5 j# B& W) h
qdhcp-85925305-b477-4cc6-9654-67d9bf1e7cd8 (id: 2)
2 {2 P3 T2 n: k: K, J5 f$ @2 Z' Nqdhcp-971ffda2-e567-40a0-a2c8-b31a577fd4d3 (id: 1)
+ d& ~! L; e% w# a+ g) ^qrouter-39a77439-8a28-49c1-bf97-ac931510631b (id: 0)
- X, A4 ]% e H# i: A" S, h . i6 I/ q4 g9 f' C7 ~! A
(3)示意图:4 {# x4 x: k e( f3 U
* r: t9 g$ Y8 p2 M, G' Q+ i
(4)说明:
1 Z2 `/ G' Q1 i2 J( h• qdhcp 和 qrouter 都是 linux network namespace 实例/ q- C: \! ?6 m0 W4 E& ?
• qdhcp network namespace 的数量等于启用了 DHCP 的 Neutron network 的数量。) R" _, m# v3 f5 `3 F* e
o 当一个 network 中存在至少一个 subnet 启用了 DHCP 之后,会有一个 qdhcp network namespace 被创建出来;
1 p) ]* Q; r( D' uo 当一个 network 中多个 subnet 启用了 DHCP 时,它们共用一个 qdhcp,以及 dnsmasq。
. W2 c1 I+ n0 m W7 W( B7 I3 n) no 其 name 使用 network id,比如 qdhcp-85925305-b477-4cc6-9654-67d9bf1e7cd8: b y' [; f$ P. a( T' b' d4 w1 r9 m
• qrouter network namespace 的数目等于 router 的数目,也就是说,系统中一共有几个 router,那么就存在几个 qrouter network namespace6 b& |8 `7 R: H+ S% m' ?" p) m0 \
• brq linux bridge 的数目等于 neutron network 的数目,其 name 是 network id 的前几位,比如 brq96609bfa-0e
' k+ i: F) N8 a( K S }# X• 一个 network 的 qdhcp network namespace 和其 brq linux bridge 一定有连接
8 S _! s5 S* N, Z0 r! r• qrouter 之内的 network interface 分两种,一种是 qr 开头的,每个连接到 router 之上的 subnet 都有一个;还有一个是 qg,每个连接到 router 的 external subnetwork 有一个
; M0 a% a |- z+ B• qrouter 的每个 network interface 都通过 veth 连接到所在网络的 qbr linux bridge 上
( i( \* ]; k* A• qbr linux bridge 连连接两种物理设备,一种是 vxlan interface,每个 tenant network 有一个,另一种是在 physical network 对应的物理网卡上创建的子接口(sub-interface)
) i3 {; a4 t$ ]6 s; ~• 对于 physical network 的 qbr 来说,用户可以指定它,并且在linuxbridge_agent.ini 中通过 bridge_mappings = List of <physical_network>:<physical_bridge> 进行配置;也可以不指定,此时 agent 会创建它。当同时配置了 physical bridge 和 physical interface 时,前者优先。1 o& E2 j0 @& O0 v
如果 external network 中有多个 subnet 的话:
% g( a; P0 |" L" M; S9 b(1)每个 qrouter 只允许有一个 External Gateway,也就是说它只有一个 qg network interface。当 external network 添加多个 subnet 之后,只有第一个被当作 external subnet,其余的都会被当作 internal subnet。7 h! i7 H6 i( E6 R5 R* ^
(2)在 qrouter 的路由表之中,
- @! v2 f/ f" Q9 L1 ?, a$ ~# A
, @0 c, [ p6 eroot@controller:/home/sammy# ip netns exec qrouter-39a77439-8a28-49c1-bf97-ac931510631b route
\* a: t* X! {7 u1 QKernel IP routing table
8 ~, W. H. e3 g4 `' x+ \1 n, xDestination Gateway Genmask Flags Metric Ref Use Iface
4 Q1 t0 p5 y, R1 p8 kdefault 10.62.227.1 0.0.0.0 UG 0 0 0 qg-e09fce07-cd' L s% c# i( n4 `# _7 O( O
10.0.0.0 * 255.255.255.0 U 0 0 0 qr-b1eaae00-e5, L6 M5 t8 `! J; c# N0 Y
10.62.227.0 * 255.255.255.0 U 0 0 0 qg-e09fce07-cd
" o4 \. y& v$ O5 X10.62.228.0 * 255.255.255.0 U 0 0 0 qg-e09fce07-cd
; B! s5 j5 h( G5 v$ v10.62.228.0 * 255.255.255.0 U 0 0 0 qr-124ff148-b73 V3 e5 K5 l1 Q" h
11.0.0.0 * 255.255.255.0 U 0 0 0 qr-16d9b0cc-380 Y4 v5 j n( ~! L- l5 ]
20.0.0.0 * 255.255.255.0 U 0 0 0 qr-0bb8efeb-10
* v- U7 U! A% M% l1 o1 k) r, K $ E( W/ i/ p/ N: [8 h* ~
5 e7 C7 r# m8 E# ]. J( A8 x
2. linux-bridge-agent 工作过程分析
+ h8 y8 F% g9 e(1)linuxbridge-agent 会启动一个循环,不断扫描上面红框中的 tap 设备
& w" R l7 p7 l8 D3 e1 r
2 a \2 x9 V. Z# P5 E def daemon_loop(self):1 A: o4 a, m. e3 g( W3 V
...* G" P. z. g8 m: U
while True:4 z1 s3 H' N ~5 {6 V( C4 b g- J
start = time.time()7 W5 U+ Z. f. N9 |. X. I
. ..
, s/ F+ b" S' A$ k2 @9 J
, D- b3 _1 P5 K7 ? device_info = self.scan_devices(previous=device_info, sync=sync)8 N+ S- O1 O- S5 S
sync = False5 _1 ~; d+ O' H3 I) Q' }8 x6 @: ^
. L5 q8 o0 u% N+ P5 _; P* `7 I% G
if (self._device_info_has_changes(device_info)
p" w" b# X: Z% t, N- k- n or self.sg_agent.firewall_refresh_needed()):( e- Q, I2 F3 m m# k5 o6 K
LOG.debug("Agent loop found changes! %s", device_info)
9 o* {* ?4 S* r% I; X, h- g* P; i try:
0 s' k$ y% o& E( ~ sync = self.process_network_devices(device_info)0 _6 v; C) A; e7 E
except Exception:% w# |( \3 {5 ]% b; z: R T
LOG.exception(_LE("Error in agent loop. Devices info: %s"),
) k) @3 v c- B device_info)7 O |0 ^( m0 t" ]
sync = True6 R4 T8 V5 T+ z" \2 O) E/ a
4 r, q& s0 }# @/ V
这是它首先找到的 devices:/ z7 p; @1 m t4 Q
(Pdb) p bridge_lib.get_bridge_names(). S# ^ N) Z- n% s( M5 a7 c
['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']2 E. T8 t% F! p0 M
然后过滤出 tap 设备:/ A0 z: u) a1 q0 D/ w' X' G9 d0 @3 y
get_all_devices()->set(['tap0bb8efeb-10', 'tap60dbdc2f-a0', 'tap795e6e86-94', 'tap798c87d1-a2', 'tapb1eaae00-e5', 'tapf70543dd-0f'])
9 w( j' f1 ^" B$ ^2 L8 o(2)根据 previous 中保存的历史数据,再接合服务器端和本地更新时间,计算出需要更新的tap设备列表:/ N2 d9 l- j Q
{'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([])}' L2 f; p1 D+ o) I/ y* [; ]; ?7 u
(3) 通过 RPC 获取 tap 设备的详细信息( t! e* E) H" E9 g2 j5 F3 H
* V$ I, }: [+ U" ~(Pdb) p devices
0 n/ |1 G0 F+ M( d/ s; Uset(['tapf70543dd-0f', 'tap60dbdc2f-a0', 'tapb1eaae00-e5', 'tap795e6e86-94', 'tap798c87d1-a2', 'tap0bb8efeb-10'])0 ]' m4 F; n) h" i
( P$ U ~ i* |+ N% q9 d' j5 Z8 J6 H7 t# z4 F4 O
devices_details_list = self.plugin_rpc.get_devices_details_list9 T# U1 u, N' G9 ^
. l" [9 {. p% B+ f: `(Pdb) p devices_details_list5 ~( ?- b$ z% L; ^, `" L0 H3 ^
[{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': []}]
, A' w/ Z! n" V1 o% j& I1 O. G; d# S4 Q + E0 s7 y5 G- S i# X4 h. w$ l
(4) 对需要处理的设备,调用 self.process_network_devices(device_info) 函数进行处理
, ~) S% O+ p' l( ^(5). 调用 plug_interface4 ?+ T# J1 a6 j, g
interface_plugged = self.mgr.plug_interface(network_id, segment,device, device_details['device_owner'])" W( ~6 Y9 B9 Q! ~. R3 \
(6). 需要的话,使用已经配置的或者新建 linux brige,并将 physical interface 设备加入其中/ V" e# k2 o8 t3 M: s& ?# |& F
bridge_name = self.get_existing_bridge_name(physical_network) #获取为 physical network 配置的 linux bridge7 H( a( ?5 C* Y5 A( ` D. k; W3 o y
bridge_name = self.get_bridge_name(network_id) #或者根据 network id 生成 bridge name
' z# D( U* w) O7 }(7).根据不同的网络类型,分别处理 vxlan bridge,flat bridge 和 vlan bridge( E" Z$ _: K5 s3 V7 d8 x7 A
& d% L5 a; ]! `& i' W+ T def ensure_physical_in_bridge(self, network_id,
+ k- s( d; r# \5 g3 M+ d network_type,
3 ^0 Z3 r$ Z J7 T: a8 q* X! Z physical_network,0 t8 O1 ^; E7 T# p8 a: w, b" ^: i
segmentation_id):& ~# F; w/ m: k
if network_type == p_const.TYPE_VXLAN:$ `: \0 ]. x/ r) y+ q H+ p
if self.vxlan_mode == lconst.VXLAN_NONE:6 \/ d4 ]$ }0 \
LOG.error(_LE("Unable to add vxlan interface for network %s"),
$ c, s5 l2 M. R7 P network_id)4 s7 _- O( U; p6 }+ X
return
. W! ^( [9 m5 o return self.ensure_vxlan_bridge(network_id, segmentation_id)
+ {/ f& n+ {1 C$ b6 d7 v1 I: `/ ^8 r. T) l
# NOTE(nick-ma-z): Obtain mappings of physical bridge and interfaces
7 A2 x' f4 U/ h8 a) i8 j: J2 d \ physical_bridge = self.get_existing_bridge_name(physical_network)
1 ~3 ?8 ^5 {9 h8 w. B! t physical_interface = self.interface_mappings.get(physical_network)! C$ ^: v% r& |9 E# ?2 Y8 z+ K
if not physical_bridge and not physical_interface:
+ k$ R, E+ O, c3 L$ g; z+ k2 H LOG.error(_LE("No bridge or interface mappings"3 a3 U9 x* {3 z) t1 a' U3 U" U
" for physical network %s"),
7 }. s, c( I n1 Y8 g' M physical_network)# [- O- Q( ?7 _- [
return
8 k, q" l5 R! E+ k if network_type == p_const.TYPE_FLAT:/ o( W, O: Q1 `
return self.ensure_flat_bridge(network_id, physical_bridge,
g7 m U: ^# O7 e/ X7 {2 |" n5 t) t physical_interface)
2 j; d' [' Q8 r elif network_type == p_const.TYPE_VLAN:
- A0 N9 V- i# ~ return self.ensure_vlan_bridge(network_id, physical_bridge,* ?/ b/ ~+ n9 f# m( a) h4 R1 z
physical_interface,
$ w4 j( F! M& f7 r) G segmentation_id)/ v: ~4 m. p* `1 l2 A( O
( x. F0 B/ e0 i9 y! ~- D
对于 flat 类型的网络,调用 ensure_physical_in_bridge. E- q; Q" t+ J/ E1 t' k
def ensure_physical_in_bridge(self, network_id,network_type,physical_network,segmentation_id)/ g$ M( x" m/ T7 n" R" e
if network_type == p_const.TYPE_FLAT:- Q; w) W c( Z
return self.ensure_flat_bridge(network_id, physical_bridge,physical_interface)
6 Y8 y( j7 B$ Z: a如果有配置 physical bridge 的话,使用它;否则创建 bridge,并将物理网卡配置的 ip 地址和 gateway 从网卡挪到 linux bridge
3 N9 t" E7 p+ m 4 }* E7 Y9 Y% d1 W+ L. g
def ensure_flat_bridge(self, network_id, phy_bridge_name,physical_interface):7 D% G1 H! k& a5 l* w
"""Create a non-vlan bridge unless it already exists."""
4 f! O, a, y# u9 d) X* S% {/ f' \. J% ] if phy_bridge_name:* C0 s9 l5 ]# l- ?# x
return self.ensure_bridge(phy_bridge_name) #获取预先配置好的 linux bridge, _2 Q% D$ R# `5 e6 O
else:
& P$ {" a3 I7 x bridge_name = self.get_bridge_name(network_id)
; h+ Z0 h5 N# p ips, gateway = self.get_interface_details(physical_interface)
, w7 `) T% s" G2 ]* f- @ if self.ensure_bridge(bridge_name, physical_interface, ips,gateway): #创建 bridge" K0 o% A1 K$ O7 i" b
return physical_interface
' B6 V8 A) R+ ?2 a$ e4 P4 S
; {! g( D* ^/ m) m |- X对于 vxlan 类型的 network,需要创建 vxlan interface' ^% b. f7 _; _ O4 F/ V
) h; M/ x$ s" s4 f1 @ def ensure_vxlan_bridge(self, network_id, segmentation_id):2 T* j. l' n% _ }
"""Create a vxlan and bridge unless they already exist."""
+ j* T8 Z' c8 A! v& ^5 a! f interface = self.ensure_vxlan(segmentation_id)
8 g8 x' M' W2 f3 [' E8 D. K) `5 M if not interface:7 [* N6 R2 O% q% a9 O, H
LOG.error(_LE("Failed creating vxlan interface for "
?& y$ r# c5 p7 c* x- _ "%(segmentation_id)s"),
* {. m5 y5 L: R: q* n( I8 V {segmentation_id: segmentation_id})
3 W. H/ J( g1 `& i% o& s return+ `, n; e# R7 ` `+ m. o
bridge_name = self.get_bridge_name(network_id)
; X" E4 A+ z' D$ n1 h: e self.ensure_bridge(bridge_name, interface)' ?8 [! S2 c1 Q1 y( [
return interface( r. ~; w2 r: \+ n& \: ?$ U( p
@$ E* W, r7 y6 }创建 vxlan interface:
* T* H1 g4 B' P0 p : X: `6 G5 ~5 W( t1 z! S, F% d
def ensure_vxlan(self, segmentation_id):+ ~6 h8 n% V3 i* V4 A, k7 `
"""Create a vxlan unless it already exists."""
- o" J% }; F7 w interface = self.get_vxlan_device_name(segmentation_id)
+ `) s. Z$ R/ z3 e* r if not ip_lib.device_exists(interface):0 c+ y) i" l6 c7 A" ^
LOG.debug("Creating vxlan interface %(interface)s for "* w0 e( w6 l6 f2 Y$ o
"VNI %(segmentation_id)s",8 B* A( `+ D' d' p
{'interface': interface,
: a2 i4 K2 K4 Y- m y 'segmentation_id': segmentation_id})
& z5 K$ v1 x' x8 ]1 A( t! T args = {'dev': self.local_int}
! C' {% i" Y2 Y7 h( V if self.vxlan_mode == lconst.VXLAN_MCAST:: H8 {) S1 R; a8 h9 f2 `2 O2 S
args['group'] = self.get_vxlan_group(segmentation_id)
5 {: \! M6 T c; Y+ H8 Z if cfg.CONF.VXLAN.ttl:1 u0 s1 |/ Z' h8 _
args['ttl'] = cfg.CONF.VXLAN.ttl
) k; S8 j6 D- G6 @: p0 | if cfg.CONF.VXLAN.tos:
$ B9 ?( H% b) K. K args['tos'] = cfg.CONF.VXLAN.tos+ c# Q, o2 H; ]6 D
if cfg.CONF.VXLAN.l2_population:
% ^( L6 {3 D' o" ?9 P args['proxy'] = cfg.CONF.VXLAN.arp_responder5 a( o; k, Z+ I, \0 ~0 I
try:/ W& @6 V0 b" R
int_vxlan = self.ip.add_vxlan(interface, segmentation_id,9 l, e5 Z% u0 [, \6 l
**args) T- i2 T% e; w/ i( }
0 G* F$ R5 c i; V2 V. e(8). 将 tap 设备加入到 linux bridge 中
$ s5 q9 j3 a$ l* W+ d/ K: i8 L0 ybridge_lib.BridgeDevice(bridge_name).addif(tap_device_name)
5 \: Q9 |$ n7 b; ~0 J' l(9). 如果将一个 tap 设备被删除,那么 linux-bridge-agent 会发现:7 u1 y! | M; P
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'])
: J1 Y) t( w' I9 M# Q2016-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
5 b" F3 X) \+ A) t+ y4 O2016-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.' V7 M+ @( H. e3 r( V
3. 关于上述工作过程的简单结论
1 M8 m6 k# ^1 E/ y, o5 u( |* H& S3.1 简单结论
( ~; r. {9 _6 u! a& e* ?1. l3agent 和 dhcpagent 创建 network namespace 时创建 tap 设备,和 network namespace 中的 interface 是一对 veth pair。当手工删除 tap 设备时,相应的 veth endpoint 也会被删除。/ j% ], A5 t" F5 K9 M: W
2. linuxbridgeagent 不断扫描服务器端和本地的 tap 设备! M) S ~& W$ d! C; m8 L9 i' M
3. linuxbridgeagent 获取需要增加和修改的tap设备列表3 o* l! X5 }4 ]
4. 对于需要增加的 tap 设备,获取其详细信息,主要是 network_id,network_type,physical_network,segmentation_id,device_owner 等,然后根据这些信息,创建 linux bridge,并加入所需要的 interface+ Q/ }; C# @0 P% a& y
5. 创建所需要的 linux bridge,并将 physical interface (provider network 的 physical interface 或者 tenant network 的 vxlan interface)加入 bridge,并且将 tap 设备也加入该 bridge0 o! q3 K5 z* M# H, G
6. 如果发现某个 linux bridge 没有创建出来,首先需要查看有没有相应的 tap 设备存在;如果 tap 设备不存在,则查看相应的 qdhcp 或者 qrouter 中时候有interface* B6 M0 q' u. O: l* @
9 F1 }6 Z- b; Z: [
具有多个 VLAN 租户网络时候的网络元素示意图:
# t0 X- P& }& t7 Y" u 5 X/ z% {. D6 _- N3 z3 i
0 Q! i4 ^. F! l! X( R" \+ r N
& K: s& @0 G7 G' B
; a& X' n. K( X
3.2 关于 unnumber interface$ V8 c% F- F2 M) l( |6 R+ x! F/ b
OpenStack 官方的 host networking 配置中,连接外网的 interface 可以是 unnumbered 的,从字面意思理解,就是该 interface 上不需要配置 IP 地址。
p( ^ ?7 S! Q) F2 u
% T% }, {6 z& b _配置的时候,修改 /etc/network/interfaces:2 H( A" j( y% q: Y
# The provider network interface
8 I- @! D; f8 Q' T! }* Xauto ens2246 s0 q. N4 `9 n- K
iface ens224 inet manual8 ]- F% E5 n6 C$ C' {3 v! V: Z
up ip link set dev $IFACE up" n! u' O# k1 ]
down ip link set dev $IFACE down, j1 ?) M$ e: A! W6 C
配置好以后:
6 ?7 R8 `, {! D
% I4 c: I/ W2 ~ D. J3 Oroot@controller:/home/sammy# ifconfig ens224# H o5 v; ~/ S1 ]2 f$ Z
ens224 Link encap:Ethernet HWaddr 00:50:56:9c:4d:94" f) i7 O" P) P/ N4 [7 e& q! T4 h( c
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:16 v+ Z j: @! ^8 {
RX packets:27300737 errors:0 dropped:0 overruns:0 frame:0
2 Q i O8 J+ F0 l x3 B TX packets:61547 errors:0 dropped:0 overruns:0 carrier:0; w0 V# ]/ a0 K8 j: b
collisions:0 txqueuelen:1000
6 v5 d; Y( l* g% ~: \- d0 j3 k RX bytes:31951077598 (31.9 GB) TX bytes:5966060 (5.9 MB)* _& r+ }8 o: m9 V' i
# n4 r8 Y: K& I% }! c$ \
root@controller:/home/sammy# ifconfig brq96609bfa-0e
( d Q( V( E3 w% c, |; Vbrq96609bfa-0e Link encap:Ethernet HWaddr 00:50:56:9c:4d:94. Y: P# x, s$ }/ ~( t: }
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:14 {' u9 x5 A) v H) w
RX packets:32855 errors:0 dropped:0 overruns:0 frame:08 D) B3 l1 G* R4 q* p
TX packets:2 errors:0 dropped:0 overruns:0 carrier:0
! a7 @" K+ d" m% d: w/ d! |' t collisions:0 txqueuelen:1000
' M. ]1 R1 J) o( J; n RX bytes:2731030 (2.7 MB) TX bytes:84 (84.0 B)/ t4 B. Z! R" T
; W+ x2 a0 \, A) F
具体原理不详,但是应该是因为 qrouter 的 qg network interface 和物理网络中的路由器的网卡之间是网络二层,因此中间的设备都是属于二层的,因此不需要处于网络三层的 IP 地址。
# h1 |) H" L `6 t( ` T4. 使用 linux bridge 时的拓扑结构
( C( c! c: R! l+ I5 C* s* t4.1 网络节点上; N' z1 \5 y" }# j E# b
为了更清楚,我们来对比着看 linux bridge 和 ovs 的两种方案:
9 q" t4 a4 B# Plinux 方案:9 I; c, ^ S5 }' O
$ D, t9 x7 W* T网络服务:! z& h/ y/ b, A& y
• Linux bridge agent
1 Q# y" U* C# @: O! ]& \% M• L3 agent
; s- C1 g+ y- c1 w• DHCP agent
% z2 t/ b: _) Y# t( l• Metadata agent: X$ r5 [5 K" Q' y8 G
Linux bridge agent 会为每个 VLAN 虚拟网络创建一个 VLAN Bridge,它连接多个网元:
1 g5 U) b7 ~- {+ V0 M• VLAN 子接口,从物理网卡(图中的 interface3)上创建,每个子接口对应一个VLAN ID,其名称格式为 device.sid,其中 device 是物理网卡名字比如 eth0,sid 是 vlan id。8 z. Q1 ^9 }8 o! {; \
• 连接虚拟机的 tap 接口+ {1 I% Z% S: _8 I
• 和 qrouter 连接的 tap 接口
0 a9 t2 w5 w+ ~$ j7 }• 和该网络的 qdhcp 连接的 tap 接口
- x8 P; g4 d- c1 [如果同时有 VXLAN 虚拟网络的话(linux-bridge 不支持GRE 隧道模式),会为每个 VLAN 虚拟网络创建一个 Tunnel bridge。它连接多个网元:) [: D0 S2 c8 x% {5 |3 }
• vxlan interface,这种接口每个虚拟网络一个,名字格式为 vxlan-sid,其中 sid 是分段ID。' ], \4 k) o6 O" W& h( n7 F6 J! M& Y
• 连接虚拟机的 tap 接口5 L" i; v: ^! K5 `$ y1 [' T: h
• 和 qrouter 连接的 tap 接口2 Z7 ?3 K0 L; C& G1 u) @
• 和该网络的 qdhcp 连接的 tap 接口
6 g! L k) e$ Y: {6 I- |# x安全组规则在 tunnel bridge 和 vlan bridge 上。7 K4 h* L6 s5 ?0 x* S1 x' r
OVS 方案:) h7 Q3 P R& y( u* H6 G0 s
$ Y4 p. L9 L6 R6 t这里面,br-int 会负责加本地 VLAN 标签,br-tun 会负责将 VLAN ID 转换为 VXLAN ID。+ V9 f$ Q1 \& {+ K* Q7 p
, Y* w- `! c) F8 M z* |) K8 G% F( X4.2 计算节点上
) \ E; l& r. r$ [4 B0 C, Z同样来对比着看。
: {7 D- x' ^/ T( `1 b1 ?* Y8 Klinux bridge:: Z) E6 B1 v- q, Z& e2 D" W* V
( I% k3 L- ?0 W4 ~网络服务:3 M3 B' d$ A% p+ G) E3 A) m! G
• Linux bridge agent' ~& v' p9 @ [0 }( q) `; |
和网络节点类似,只不过没有 qrouter 和 qdhcp,不在赘述。, r: a/ \+ e6 s& i+ a. l
OVS:
0 a3 _+ b |% [) x" M
) R! N& \7 _3 U6 r8 U- P7 I; B
$ |7 d0 k2 L9 M8 P' t; Q5 d% dOVS 放在在 br-int 上实现 VLAN 标签,在 br-tun 上实现隧道,在 qbr linux bridge 上实现安全组。
8 x$ J& y6 @8 o, B * C: V. e( d% Q. y
4.3 网络路径 - 南北向网络流向% m0 V$ _& l9 P% x+ ~0 p8 n8 [
* O: L/ ~1 ^4 o2 @2 u5 t9 s c6 dVLAN 网络和VXLAN 网络井水不犯河水。这图上的配置中,计算节点和网络节点上的物理网卡都分开了。
4 x- n2 x+ C( r! f4 s4.4 网络路径 - 东西向(不同网络)
* L1 A+ \# w+ g0 j2 G ( Y/ p/ S# G7 p8 o; n' e) y2 m" i
4.5 网络路径 - 东西向(同一个网络)+ e3 Q3 I0 h7 ]% e t
/ [. y& b% e8 m+ q " t+ `5 y6 A3 M
请详细说明和配置,请参阅参考文档。
8 w5 {- o3 P5 ?5. 一点结论
% |, N' T- ]- D( Y3 J和基于 OVS 的二层网络相比,
0 ~1 B5 O3 V( G; B5 k• 功能和架构上:基于 linux bridge 的实现还是有一些短处,比如每个虚拟网络就需要一个网桥,这在大规模环境中会带领资源使用和管理上的问题。其好处是本身架构比较清晰。/ _- Q, ^& c: \3 D2 I, L5 S- f
• 性能上:基本上差不多,如下图所示,不管是 vxlan 还是 vlan。
3 M a& v2 [2 m* c& U* Y% g 8 C' S. \: p+ h, ^4 j
|0 i# ~5 r0 }: w+ p
|
|