|
前言 本文先介绍一下VLAN Trunk的基本概念,以及OpenStack Neutron和OpenFlow based SDN是如何为Trunk port提供网络支持。OpenStack对VLAN Trunk的支持具体是什么?虽然OpenStack与容器,物理主机也做了集成,但是OpenStack最主要的应用还是虚机管理,而现代的操作系统,不论是Linux还是Windows,都支持将网卡配置成Trunk port。OpenStack对VLAN Trunk的支持就是指对OpenStack所管理的虚机的Trunk port,提供网络支持。7 y \+ |3 r# N( K' f* ?% Q

) J4 X- E4 A8 H& w( N) K主机的Trunk port是指在主机的一块网卡上添加多个带有不同VLAN ID的子网卡。通过子网卡发送的数据,打上VLAN Tag,被发送出去。由于带了不同的VLAN Tag,子网卡可以认为连接在VLAN Tag标识的网络中。这样,不用增减主机的网卡,就可以将主机添加到新的网络中。更主要的是,这种方式的网络添加是动态的。 主机的Trunk port有什么用?一个应用是在NFV场景下,一个VNF(Virtual Networking Function)可能需要同时连接多个网络。当然最简单是一个网络对应一块网卡,但如果网络数量巨大,网卡数量也巨大,一方面这不现实。另一方面,连接的多个网络也是动态增减的,如果每次增减都插拔VNF的网卡,明显也是不能接受的。如果用Trunk port,当需要动态连接多个网络时,只需要动态的创建/删除相应的子网卡即可。! y4 \# T: b6 ]! n) l3 _
VLAN Trunk在NFV中的应用 一、VLAN Trunk介绍1.1 VLAN简介VLAN(Virtual LAN)由IEEE802.1Q定义。要讲VLAN要先从广播域(Broadcast Domain)开始说起。在下图中,假设PC1-5在一个广播域中,当PC1发出广播帧,例如ARP,DHCP,由于目的MAC地址是广播地址,同一个广播域内的所有设备都将收到相应的广播帧。如果PC1-5在一个子网中,那这本身也无可厚非,因为这正是ARP,DHCP的工作原理。( a- ^: ]$ @4 q

) m& S4 z; D0 }* |2 |9 A# H6 \如果PC1-5不在一个子网中呢?例如上图中,PC1在橙色子网,PC2-3在绿色子网,PC4-5在红色子网。理论上,PC1发出的广播帧只应该在橙色子网内传播。但实际上,是由于PC1-5在一个广播域中,PC2-5还是会收到PC1的广播帧。虽然PC2-5会直接丢弃这个广播帧,但是这里存在安全问题和性能问题。首先,PC2-5虽然不会处理PC1发来的广播帧,但是数据还是发送过来了,通过侦听和伪装,可以达到劫持的目的,例如ARP spoof。其次,广播帧本来不用在整个网络传播,但现在就整个网络传播,这样占用了交换机的带宽,在大规模网络中,尤其会影响网络性能。解决这些问题的方法就是使用VLAN。 VLAN是一组网络端口的集合。实现了VLAN的交换机,会将二层的单播、组播、广播都局限在一个VLAN中,这样不同的VLAN中的主机,交换机就不会有其他VLAN的数据。只有交换机能看到VLAN,连接交换机的其他设备,例如Server、Router都感觉不到VLAN的存在。将不同的子网规划在不同的VLAN当中,可以实现子网的隔离。即使所有的设备都在一个交换机上,不同的VLAN之间通信也需要通过Router。
0 T8 q6 X0 D, N* N5 ?- S 1.2 VLAN Trunk简介VLAN的划分并非只能在一个交换机上,多个交换机可以共同组成VLAN。那多个交换机上的VLAN是怎么连接到一起的?有两种方法。 第一种方法是把每个交换机上的每个VLAN都连在一起。如下图所示:
8 h* N! S4 x9 P: J* ?
* {+ U" Y% _" ` |3 H8 a- C G2 ^& h7 H图中有两个交换机,各有两个VLAN,为了让VLAN能正常工作,将VLAN1和VLAN2分别连接起来。如果是两个交换机,两个VLAN还好,如果是100个VLAN,那么这里需要有100条线路,200个交换机端口。这么连接可以吗?可以,只要有钱,因为这里的线路和交换机端口都是钱。这种方法,运维和成本支出比较大,不实用。 第二种方法是通过VLAN Trunk连接交换机。VLAN Trunk是一种网络设备间的point-to-point的连接。一条VLAN Trunk线路可以同时传输多个甚至所有的VLAN数据。
f# u" ^) c/ |7 {, l C7 `
* B% Q9 ~5 |; _1 p! z由于VLAN Trunk可以传输多个VLAN数据,Ethernet Frame在VLAN Trunk上传输时,需要带上802.1Q定义的VLAN tag,这样交换机才能区分Ethernet Frame到底属于哪个VLAN。VLAN Trunk的具体使用过程如下: - 当最左侧服务器想要访问最右侧服务器,最左侧服务器将Ethernet Frame发送到左侧交换机
- 左侧交换机本地没有目的MAC对应的转发信息,因此Ethernet Frame发送到了左侧交换机的VLAN Trunk port
- 由于这是来自VLAN100的Ethernet Frame,交换机给Ethernet Frame打上VLAN 100的Tag,从自己的VLAN Trunk port发出,发送到右侧交换机的VLAN Trunk port
- 右侧的VLAN Trunk port收到VLAN 100的Ethernet Frame,去除VLAN Tag,再在本地的VLAN 100端口中查找MAC转发
- 找到对应的MAC/端口记录,最终Ethernet Frame发送到最右侧的服务器
" s/ S( q `2 {
如果是VLAN200的数据,过程一样,只是VLAN Tag从100变成了200。 通过VLAN Trunk port,两个交换机之间不论需要连接多少个VLAN,只需要一个VLAN Trunk连接(一对Trunk port)即可。 如果有多个交换机需要连接,通常会用另外一个交换机连接它们,如下图所示,交换机之间都通过Trunk port相连。 P* O) J( I: G h% Q

/ N( ?7 B/ R8 m/ ?红色框内的交换机的4个port都是Trunk port,任意的VLAN 标签的Ethernet Frame都可以在这个交换机内传输。可以把红色框内看成是一个Trunk network,一个Trunk network可以传输带VLAN标签的Ethernet Frame。虽然图中只有一个交换机,但是Trunk network可以更加复杂,由多个交换机组成。多个VLAN的网络数据共同在Trunk network上传输,通过VLAN Tag来识别VLAN。 如果把上图中下面四个交换机换成主机(虚机),那就是OpenStack VLAN Trunk希望支持的场景。为了支持这个场景,需要为虚机提供一个Trunk Network。 1.3 Linux VLAN TrunkWindows也支持Trunk port,与Linux类似,这里只说明Linux系统下的Trunk port。 Linux系统可以通过内核模块8021q支持VLAN Trunk。这里有什么不一样?在一般情况下,主机是不感知VLAN Tag的,也就是说主机发送的网络数据都是不带VLAN Tag,所有VLAN Tag操作都是由交换机完成。但是实际上交换机也不知道自己连接的是什么,所以,如果在主机完成VLAN Tag的操作,再发送到交换机,交换机也能处理。基于这个前提,Linux能够将一块以太网卡配置成一个支持802.1q的Trunk port,使得这块网卡跟前面描述的交换机上的Trunk port一样,能够收发多个VLAN的网络数据包。并且通过配置Linux主机的子网卡,可以使得Linux主机内部完成VLAN Tag的操作(打上VLAN Tag,去除VLAN Tag)。有不止一种方法可以配置Linux VLAN Trunk,这里以ip命令为例,为eth0添加名为eth0.102的子网卡,其VLAN ID为102。 [color=rgb(51, 51, 51) !important]
7 n4 m$ F4 s7 H) m6 c; h' k 0 w6 Y6 O* N. b3 g2 \
2 J, G8 Q* }1 j, L 9 E# e) o! e! a) v
/ `6 B, t4 [( o6 Z
) X/ r* s j0 n* e5 k& s$ R5 X4 C: n
4 u* @- p; j9 b9 p& r6 E E2 w' D3 R
! M( c7 R" |% Z 4 Y) J/ d5 |/ X
[color=rgb(153, 153, 153) !important]Java 7 e) f- _+ A8 T c8 I3 ?
2 e7 ?. \$ }* l: X% X1 x) a
" R+ B0 d8 B& q4 T1
7 t8 m0 t( O5 H+ t. z6 p1 G ) b) e) {: L- w3 G
| [color=rgb(51, 51, 51) !important]$[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]sudo [color=rgb(0, 78, 208) !important]ip [color=rgb(0, 78, 208) !important]link [color=rgb(0, 78, 208) !important]add [color=rgb(0, 78, 208) !important]link [color=rgb(0, 78, 208) !important]eth0 [color=rgb(0, 78, 208) !important]name [color=rgb(0, 45, 122) !important]eth0[color=rgb(51, 51, 51) !important].[color=rgb(206, 0, 0) !important]102[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]type [color=rgb(0, 78, 208) !important]vlan [color=rgb(0, 0, 0) !important]id[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]102 : X+ U0 e$ ~: M
! Y- I7 t; W+ Z
|
. }, Z( o8 B4 {) B8 x
* U8 X! e2 G5 f5 n
就这么简单,之后可以看到一个新的网卡在系统的网卡列表中。Linux VLAN Trunk工作过程如下: - 外界传入的带VLAN Tag 102的包,到达了eth0,VLAN Tag 102被去除,然后不带VLAN Tag的Ethernet Frame被重新发往操作系统网络栈,再发送到eth0.102。
- 从eth0.102发送出来的帧,被打上VLAN102的标签,再从eth0传出。
9 H0 {3 w R% x8 V
应用层面,收发的还是不带VLAN Tag的数据,只是经过Linux VLAN Trunk的处理,进出主机的的数据是带VLAN Tag的数据。 由于eth0配置成了VLAN Trunk port。为了让带有VLAN标签的Ethernet Frame能够在网络上传输。eth0所接入的网络必须是一个Trunk network。否则无法传输任意带VLAN Tag的Ethernet Frame。也就是说,需要将主机的Trunk port连接到红框内。接下来我们看看OpenStack是怎么做的。 二、OpenStack Neutron对VLAN Trunk的支持Neutron VLAN Transparency这是OpenStack Kilo版本的特性,由VLAN trunking networks for NFV定义。这个特性为Neutron network增加一个属性“vlan-transparent”,当vlan-transparent为True时,表明在这个Neutron network是一个Trunk network。在这个Neutron network中的虚机可以使用Linux VLAN Trunk功能。接下来看看Neutron为了实现这个特性做了什么? 什么也没做!Neutron只是提供了这么一个属性,具体的实现交给底层的SDN。如果SDN不支持VLAN Transparency,可以在ML2中告知Neutron。那么用户在创建Neutron network时,如果指定了vlan-transparent=True,Neutron会返回“Backend does not support VLAN Transparency.”。例如OpenVSwitch,就不支持VLAN Transparency。 所以,并非所有的SDN都支持这个功能,就算实现了,每种SDN的实现方式不一样。不过本质上,都是将SDN控制的vSwitch配置成Trunk模式。需要注意的是,vSwitch最终还是要连接到Physical Switch,所以Physical Switch相应的端口也需要配置成Trunk port。 先来看看VLAN Transparency的问题, - 不支持OpenVSwitch
- 要求Physical Switch也配置相应的Trunk port
% e9 |! J) C7 t7 J4 I0 A
VLAN aware VMs在支持相同功能的前提下,解决了上面两个问题。首先看看如何使用VLAN aware VMs这个功能。Neutron VLAN aware VMs是OpenStack Newton版本的特性,由VLAN aware VMs定义。VLAN aware VMs和VLAN Transparency说的其实是一件事情,就是如何传递VM发出来的带VLAN Tag的帧。 2.1 实验步骤我用的是最新代码(Pike 2017-08-08)配合OpenVSwitch完成下面的操作。要使能VLAN aware VMs,只需要在/etc/neutron/neutron.conf中,在service_plugins后面加上trunk。 首先创建Trunk port所在的网络和VLAN子网卡所在的网络。 [color=rgb(51, 51, 51) !important]
2 ^# o' S6 v5 j$ z; y# a 5 j% g: N$ t3 [9 N* ~
: g V4 @" I7 X- A+ O; Q
# U! { ]$ N1 C; y) j8 L
/ C ]7 _' a. K* Z$ H5 N/ j
, H1 v2 d% N/ `1 I# D6 A8 b5 Y
' m* W3 ^5 m. X8 s" e" o
3 z: c) O' o; a5 z! A4 ]' L* }/ ?- `5 P, u! j+ A+ ~
. l+ `% I% _; ~- z3 `% m[color=rgb(153, 153, 153) !important]Java
' K4 U% L1 A) ?7 k3 v
9 w: b9 D# _+ a* ]- ^8 z5 d# P
* ]6 J. l" v" Q/ @2 D: S" {% i( W1
7 t" [: E' r- [2 J; [[color=rgb(49, 124, 197) !important]2
; \6 J/ f7 q9 ?: m! i& s3 $ B3 l, z- U# O; b
[color=rgb(49, 124, 197) !important]4 6 `' n- W6 U- z5 b/ B1 t
4 }' b: w* Q1 x- S, D0 \) j9 ]
| [color=rgb(51, 51, 51) !important]$[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]openstack [color=rgb(0, 78, 208) !important]network [color=rgb(0, 78, 208) !important]create [color=rgb(128, 0, 128) !important]parent[color=rgb(0, 111, 224) !important]-[color=rgb(0, 0, 0) !important]net
1 U( w$ n/ x' B4 L' s[color=rgb(51, 51, 51) !important]$[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]openstack [color=rgb(0, 78, 208) !important]subnet [color=rgb(0, 78, 208) !important]create [color=rgb(128, 0, 128) !important]parent[color=rgb(0, 111, 224) !important]-[color=rgb(0, 45, 122) !important]subnet[color=rgb(0, 111, 224) !important] [color=rgb(0, 111, 224) !important]--[color=rgb(0, 78, 208) !important]network [color=rgb(128, 0, 128) !important]parent[color=rgb(0, 111, 224) !important]-[color=rgb(0, 45, 122) !important]net[color=rgb(0, 111, 224) !important] [color=rgb(0, 111, 224) !important]--[color=rgb(0, 45, 122) !important]subnet[color=rgb(0, 111, 224) !important]-[color=rgb(0, 0, 0) !important]range[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]20.0.0.0[color=rgb(0, 111, 224) !important]/[color=rgb(206, 0, 0) !important]24
. D2 m6 r0 K- i$ M0 b$ G[color=rgb(51, 51, 51) !important]$[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]openstack [color=rgb(0, 78, 208) !important]network [color=rgb(0, 78, 208) !important]create [color=rgb(0, 45, 122) !important]sub[color=rgb(0, 111, 224) !important]-[color=rgb(0, 0, 0) !important]net ' K+ L& `) H' _) `( \: `: W
[color=rgb(51, 51, 51) !important]$[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]openstack [color=rgb(0, 78, 208) !important]subnet [color=rgb(0, 78, 208) !important]create [color=rgb(0, 45, 122) !important]sub[color=rgb(0, 111, 224) !important]-[color=rgb(0, 45, 122) !important]subnet[color=rgb(0, 111, 224) !important] [color=rgb(0, 111, 224) !important]--[color=rgb(0, 78, 208) !important]network [color=rgb(0, 45, 122) !important]sub[color=rgb(0, 111, 224) !important]-[color=rgb(0, 45, 122) !important]net[color=rgb(0, 111, 224) !important] [color=rgb(0, 111, 224) !important]--[color=rgb(0, 45, 122) !important]subnet[color=rgb(0, 111, 224) !important]-[color=rgb(0, 0, 0) !important]range[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]21.0.0.0[color=rgb(0, 111, 224) !important]/[color=rgb(206, 0, 0) !important]24 ' ?, b3 |+ s0 @* K& k! ?- Y @
! O; K, F" i+ F( b3 N
|
E* B9 k: P, F' i' ]6 d ) }* o* Y; b) Q3 j! i/ s1 \8 |) C; ?; @
注意这里我并没有指定网络的类型,网络可以不用是VLAN的,像在我的环境中,网络就是VXLAN类型。为什么会这样?在后面会说。 接下来创建Trunk port和subport。 [color=rgb(51, 51, 51) !important]4 d/ i7 C" n9 j" r/ s; @# ~
3 i: D# V( [1 Q( Y1 ^3 X' g
: S8 U0 Q; ]0 u, p- `% [
`: W0 b& o- f- L8 F2 }# I3 z
/ r# c2 r$ w" ?$ N0 [1 q5 Y8 M
7 F& `4 t( v8 a) z) C) `0 n
" o2 P+ J+ ]- Z0 C ; e$ g# X. n+ H
$ |( T4 o, T7 O! P; r# [( k( B
6 z7 X% [8 E- W3 P* `, V3 S( H# S[color=rgb(153, 153, 153) !important]Java
* n4 S: J: q% |- l/ h 0 U2 l1 z8 @/ z3 Z7 {
+ I' q9 {9 k/ O* Z6 m1 8 s1 t4 O3 @, I3 X3 S$ I/ x
[color=rgb(49, 124, 197) !important]2 7 N! p8 u# c$ ~2 M. N2 N w
3
/ o7 V1 L2 k) o7 {( H4 D* A/ L[color=rgb(49, 124, 197) !important]4 5 w; t! B7 V/ w/ ~# F9 X
5 , u1 i' A! M8 W& U% |
[color=rgb(49, 124, 197) !important]6 4 y: M g4 H7 [- U6 j
7 ' d0 Z: X% [5 Q7 X* i
[color=rgb(49, 124, 197) !important]8 6 y0 \6 Y6 q# Y |
3 Y" C& i5 U+ h9 K. N8 r7 d | [color=rgb(51, 51, 51) !important]$[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]openstack [color=rgb(0, 78, 208) !important]port [color=rgb(0, 78, 208) !important]create [color=rgb(128, 0, 128) !important]parent[color=rgb(0, 111, 224) !important]-[color=rgb(0, 45, 122) !important]port1[color=rgb(0, 111, 224) !important] [color=rgb(0, 111, 224) !important]--[color=rgb(0, 78, 208) !important]network [color=rgb(128, 0, 128) !important]parent[color=rgb(0, 111, 224) !important]-[color=rgb(0, 0, 0) !important]net
2 x* A! M+ _( S8 M" X2 u[color=rgb(51, 51, 51) !important]$[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]openstack [color=rgb(0, 78, 208) !important]port [color=rgb(0, 78, 208) !important]create [color=rgb(0, 45, 122) !important]sub[color=rgb(0, 111, 224) !important]-[color=rgb(0, 45, 122) !important]port1[color=rgb(0, 111, 224) !important] [color=rgb(0, 111, 224) !important]--[color=rgb(0, 78, 208) !important]network [color=rgb(0, 45, 122) !important]sub[color=rgb(0, 111, 224) !important]-[color=rgb(0, 0, 0) !important]net
: B5 V2 c/ n0 d' f. g+ A# F* G2 F' Y5 p[color=rgb(51, 51, 51) !important]$[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]openstack [color=rgb(0, 78, 208) !important]network [color=rgb(0, 78, 208) !important]trunk [color=rgb(0, 78, 208) !important]create [color=rgb(0, 45, 122) !important]trunk1[color=rgb(0, 111, 224) !important] [color=rgb(0, 111, 224) !important]--[color=rgb(128, 0, 128) !important]parent[color=rgb(0, 111, 224) !important]-[color=rgb(0, 78, 208) !important]port [color=rgb(128, 0, 128) !important]parent[color=rgb(0, 111, 224) !important]-[color=rgb(0, 0, 0) !important]port1 0 q, z6 U2 w) B F" c: ]" M* K1 ~. q5 K
[color=rgb(51, 51, 51) !important]$[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]openstack [color=rgb(0, 78, 208) !important]network [color=rgb(0, 78, 208) !important]trunk [color=rgb(0, 78, 208) !important]set [color=rgb(0, 45, 122) !important]trunk1[color=rgb(0, 111, 224) !important] [color=rgb(0, 111, 224) !important]--[color=rgb(0, 78, 208) !important]subport [color=rgb(0, 45, 122) !important]port[color=rgb(0, 111, 224) !important]=[color=rgb(0, 45, 122) !important]sub[color=rgb(0, 111, 224) !important]-[color=rgb(0, 45, 122) !important]port1[color=rgb(51, 51, 51) !important],[color=rgb(0, 45, 122) !important]segmentation[color=rgb(0, 111, 224) !important]-[color=rgb(0, 45, 122) !important]type[color=rgb(0, 111, 224) !important]=[color=rgb(0, 45, 122) !important]vlan[color=rgb(51, 51, 51) !important],[color=rgb(0, 45, 122) !important]segmentation[color=rgb(0, 111, 224) !important]-[color=rgb(0, 45, 122) !important]id[color=rgb(0, 111, 224) !important]=[color=rgb(206, 0, 0) !important]102 4 _ i$ s6 B0 ]
[color=rgb(51, 51, 51) !important]$[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]openstack [color=rgb(0, 78, 208) !important]port [color=rgb(0, 78, 208) !important]create [color=rgb(128, 0, 128) !important]parent[color=rgb(0, 111, 224) !important]-[color=rgb(0, 45, 122) !important]port2[color=rgb(0, 111, 224) !important] [color=rgb(0, 111, 224) !important]--[color=rgb(0, 78, 208) !important]network [color=rgb(128, 0, 128) !important]parent[color=rgb(0, 111, 224) !important]-[color=rgb(0, 0, 0) !important]net
6 I3 v: U/ j4 ~4 d' t[color=rgb(51, 51, 51) !important]$[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]openstack [color=rgb(0, 78, 208) !important]port [color=rgb(0, 78, 208) !important]create [color=rgb(0, 45, 122) !important]sub[color=rgb(0, 111, 224) !important]-[color=rgb(0, 45, 122) !important]port2[color=rgb(0, 111, 224) !important] [color=rgb(0, 111, 224) !important]--[color=rgb(0, 78, 208) !important]network [color=rgb(0, 45, 122) !important]sub[color=rgb(0, 111, 224) !important]-[color=rgb(0, 0, 0) !important]net / j, `1 y; b$ U, l/ n
[color=rgb(51, 51, 51) !important]$[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]openstack [color=rgb(0, 78, 208) !important]network [color=rgb(0, 78, 208) !important]trunk [color=rgb(0, 78, 208) !important]create [color=rgb(0, 45, 122) !important]trunk2[color=rgb(0, 111, 224) !important] [color=rgb(0, 111, 224) !important]--[color=rgb(128, 0, 128) !important]parent[color=rgb(0, 111, 224) !important]-[color=rgb(0, 78, 208) !important]port [color=rgb(128, 0, 128) !important]parent[color=rgb(0, 111, 224) !important]-[color=rgb(0, 0, 0) !important]port2 4 r4 |$ D- s3 [: C/ L; D% X( o/ v
[color=rgb(51, 51, 51) !important]$[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]openstack [color=rgb(0, 78, 208) !important]network [color=rgb(0, 78, 208) !important]trunk [color=rgb(0, 78, 208) !important]set [color=rgb(0, 45, 122) !important]trunk2[color=rgb(0, 111, 224) !important] [color=rgb(0, 111, 224) !important]--[color=rgb(0, 78, 208) !important]subport [color=rgb(0, 45, 122) !important]port[color=rgb(0, 111, 224) !important]=[color=rgb(0, 45, 122) !important]sub[color=rgb(0, 111, 224) !important]-[color=rgb(0, 45, 122) !important]port2[color=rgb(51, 51, 51) !important],[color=rgb(0, 45, 122) !important]segmentation[color=rgb(0, 111, 224) !important]-[color=rgb(0, 45, 122) !important]type[color=rgb(0, 111, 224) !important]=[color=rgb(0, 45, 122) !important]vlan[color=rgb(51, 51, 51) !important],[color=rgb(0, 45, 122) !important]segmentation[color=rgb(0, 111, 224) !important]-[color=rgb(0, 45, 122) !important]id[color=rgb(0, 111, 224) !important]=[color=rgb(206, 0, 0) !important]102
, t7 a8 i, s l4 Z/ X& | . B% G& _8 }6 \' p7 n' g
|
8 `" B3 H9 X, R- z5 N$ q
8 E- A! \2 b$ D1 o; z R这里创建了两组4个port,并用trunk模型将它们关联起来了。除此之外,还为Trunk中的subport指定了segmentation-type和segmentation-id。VLAN是目前OpenVSwitch支持的唯一的segmentation type(也是大多数SDN唯一支持的类型),segmentation id就是在虚机中创建subport时指定的VLAN ID。 接下来用parent port创建两个虚机。 [color=rgb(51, 51, 51) !important]
- x7 `& ~9 W, o' _9 ^7 s5 _
5 h/ W1 c% N) w. m
# w! x( m5 t' Q8 ~
. m7 l. H2 b* A. r) f; K" B' |" h; C* A
4 R1 C% ~+ y! D+ D: }0 H
( f7 I3 f' n; A0 K6 z
1 w E9 e, X# H2 i4 @% Y
1 O |, K! Z. f$ m: r$ ?7 D : c# N% C5 V( r5 ]* o0 p5 Q2 D
[color=rgb(153, 153, 153) !important]Java ) X* V W, E3 L8 O1 z
( ^& W/ p$ T5 j) t+ N m
! {! l9 b9 E, w7 V+ b% Z& _1
7 @1 ]9 \* [5 z7 ] @[color=rgb(49, 124, 197) !important]2 , J4 M! c: Z; m7 t
! U. Q" a$ ~. @0 g | [color=rgb(51, 51, 51) !important]$[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]nova [color=rgb(0, 45, 122) !important]boot[color=rgb(0, 111, 224) !important] [color=rgb(0, 111, 224) !important]--[color=rgb(0, 78, 208) !important]image [color=rgb(0, 45, 122) !important]ubuntu[color=rgb(0, 111, 224) !important] [color=rgb(0, 111, 224) !important]--[color=rgb(0, 0, 0) !important]flavor[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]2[color=rgb(0, 111, 224) !important] [color=rgb(0, 111, 224) !important]--[color=rgb(0, 78, 208) !important]nic [color=rgb(0, 45, 122) !important]port[color=rgb(0, 111, 224) !important]-[color=rgb(0, 45, 122) !important]id[color=rgb(0, 111, 224) !important]=[color=rgb(0, 111, 224) !important]<[color=rgb(128, 0, 128) !important]parent[color=rgb(0, 111, 224) !important]-[color=rgb(0, 78, 208) !important]port1 [color=rgb(0, 45, 122) !important]id[color=rgb(0, 111, 224) !important]>[color=rgb(0, 111, 224) !important] [color=rgb(0, 111, 224) !important]--[color=rgb(0, 45, 122) !important]key[color=rgb(0, 111, 224) !important]-[color=rgb(0, 45, 122) !important]name[color=rgb(0, 111, 224) !important]=[color=rgb(0, 111, 224) !important]<[color=rgb(0, 78, 208) !important]your [color=rgb(0, 78, 208) !important]key [color=rgb(0, 45, 122) !important]name[color=rgb(0, 111, 224) !important]>[color=rgb(0, 111, 224) !important] [color=rgb(0, 0, 0) !important]vm1
0 k- \0 {/ g7 `* M u& T' j[color=rgb(51, 51, 51) !important]$[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]nova [color=rgb(0, 45, 122) !important]boot[color=rgb(0, 111, 224) !important] [color=rgb(0, 111, 224) !important]--[color=rgb(0, 78, 208) !important]image [color=rgb(0, 45, 122) !important]ubuntu[color=rgb(0, 111, 224) !important] [color=rgb(0, 111, 224) !important]--[color=rgb(0, 0, 0) !important]flavor[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]2[color=rgb(0, 111, 224) !important] [color=rgb(0, 111, 224) !important]--[color=rgb(0, 78, 208) !important]nic [color=rgb(0, 45, 122) !important]port[color=rgb(0, 111, 224) !important]-[color=rgb(0, 45, 122) !important]id[color=rgb(0, 111, 224) !important]=[color=rgb(0, 111, 224) !important]<[color=rgb(128, 0, 128) !important]parent[color=rgb(0, 111, 224) !important]-[color=rgb(0, 78, 208) !important]port2 [color=rgb(0, 45, 122) !important]id[color=rgb(0, 111, 224) !important]>[color=rgb(0, 111, 224) !important] [color=rgb(0, 111, 224) !important]--[color=rgb(0, 45, 122) !important]key[color=rgb(0, 111, 224) !important]-[color=rgb(0, 45, 122) !important]name[color=rgb(0, 111, 224) !important]=[color=rgb(0, 111, 224) !important]<[color=rgb(0, 78, 208) !important]your [color=rgb(0, 78, 208) !important]key [color=rgb(0, 45, 122) !important]name[color=rgb(0, 111, 224) !important]>[color=rgb(0, 111, 224) !important] [color=rgb(0, 45, 122) !important]vm2 9 D/ @: c3 J9 F' |6 \1 P/ I
6 t& o5 W. [# `
|
5 G$ Y* B) T6 Y & g/ P" f; r0 S. v" k
因为Linux VLAN Trunk需要8021q内核模块的支持,这里用了一个Ubuntu16.04的image。 到此为止,OpenStack的操作完成了。接下来,在两个虚机内部,配置Linux VLAN Trunk。在vm1内部,做如下配置: [color=rgb(51, 51, 51) !important]9 J6 }0 a+ D2 m
$ t, v6 X% j1 y: F. A
4 J) }+ h' Q: r 2 h I6 j* y9 Q6 m% ^0 T: T4 ^+ Z* z. T
, d' o: p( u+ p! e6 t3 ~9 r1 o* d
, ?. B5 `% g! i, }
4 n; S, `. f" z9 Y/ h6 L
4 E7 v, n1 @, ?9 ^0 M
* q1 U* C' X, J( M9 {
7 g1 B) J7 T8 {0 N5 A4 ~
[color=rgb(153, 153, 153) !important]Java 3 W. _5 l0 E, w) g9 U
4 D; C r: Z* E$ L2 V$ N9 y+ I
' P5 ^% n0 _9 g5 Y( d G
1 . a) F% z. Q7 n) B+ n) v7 C6 G
[color=rgb(49, 124, 197) !important]2
0 r+ G+ n" f2 s1 `3 % H/ q. F" H4 P/ W% h
3 T% V* o. p S
| [color=rgb(0, 45, 122) !important]ubuntu[color=rgb(102, 102, 102) !important]@vm1[color=rgb(0, 111, 224) !important]:[color=rgb(0, 111, 224) !important]~[color=rgb(51, 51, 51) !important]$[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]sudo [color=rgb(0, 78, 208) !important]ip [color=rgb(0, 78, 208) !important]link [color=rgb(0, 78, 208) !important]add [color=rgb(0, 78, 208) !important]link [color=rgb(0, 78, 208) !important]ens3 [color=rgb(0, 78, 208) !important]name [color=rgb(0, 45, 122) !important]ens3[color=rgb(51, 51, 51) !important].[color=rgb(206, 0, 0) !important]102[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]type [color=rgb(0, 78, 208) !important]vlan [color=rgb(0, 0, 0) !important]id[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]102 . Y* X! |: G8 M% f, M
[color=rgb(0, 45, 122) !important]ubuntu[color=rgb(102, 102, 102) !important]@vm1[color=rgb(0, 111, 224) !important]:[color=rgb(0, 111, 224) !important]~[color=rgb(51, 51, 51) !important]$[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]sudo [color=rgb(0, 78, 208) !important]ip [color=rgb(0, 78, 208) !important]link [color=rgb(0, 78, 208) !important]set [color=rgb(0, 78, 208) !important]dev [color=rgb(0, 45, 122) !important]ens3[color=rgb(51, 51, 51) !important].[color=rgb(206, 0, 0) !important]102[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]address * N6 I2 p, Q; s5 @3 K7 y
[color=rgb(0, 45, 122) !important]ubuntu[color=rgb(102, 102, 102) !important]@vm1[color=rgb(0, 111, 224) !important]:[color=rgb(0, 111, 224) !important]~[color=rgb(51, 51, 51) !important]$[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]sudo [color=rgb(0, 78, 208) !important]ip [color=rgb(0, 78, 208) !important]link [color=rgb(0, 78, 208) !important]set [color=rgb(0, 78, 208) !important]dev [color=rgb(0, 45, 122) !important]ens3[color=rgb(51, 51, 51) !important].[color=rgb(206, 0, 0) !important]102[color=rgb(0, 111, 224) !important] [color=rgb(0, 45, 122) !important]up " f4 L8 m+ o. }5 a6 i9 @' t; T+ r3 q3 ~
) ?' P9 F% z7 M: \: A |
1 v; K% \2 s3 `( Q S: L
2 E. e) t6 j9 o S
这里给虚机的subport配置的VLAN ID是102,这是之前通过OpenStack命令创建Trunk时指定的segmentation-id。这里的ens3.102对应之前创建的sub-port1,为了让ens3.102能使用Neutron DHCP服务,这里将Neutron分配给sub-port1的MAC地址配置在ens3.102上。Linux子网卡默认会跟父网卡用同一个MAC地址,所以也可以在用OpenStack命令创建subport的时候,指定MAC地址。总之,这里我们让虚机内的子网卡的MAC地址与OpenStack Neutron中对应的subport的MAC地址一致。 在vm2内部做同样的操作,只是MAC地址换成成sub-port2的MAC地址。 2.2 验证连通性及DHCP服务DHCP服务 " U1 Q7 E+ e/ J
在两个虚机内部,通过dhclient命令获取子网卡IP地址。 [color=rgb(51, 51, 51) !important]3 k2 S2 M9 p6 l
1 w& x# F- e# }' h! o) n
. D9 m6 `+ T( s `- Z, r
5 t" s" R4 w1 M
; k, Y- o, u5 _4 X7 c1 K3 ^
& U1 Q, T: T6 s* Q6 W8 J2 N5 l
5 k5 l; B# S% R7 n& B( Z+ m- ]7 `8 } ( l' Q: ?( x; m+ f% G# B; P6 N
7 v, L2 b4 L6 f$ Y/ { ; k; \) i! C0 b% b8 H2 `
[color=rgb(153, 153, 153) !important]Java
+ N. P1 {8 C) Q1 t6 u7 V! q$ V 7 Q2 K' L; H' S+ }1 @' a- I
/ X; v8 l9 C: |3 O) q- @: e8 F1 ( \8 c: i: b7 m2 z8 X
[color=rgb(49, 124, 197) !important]2 ' |# z0 \1 t8 q$ x2 o* x, W; r
3
, R7 a5 q2 W9 S- o[color=rgb(49, 124, 197) !important]4
) i3 g w I$ B/ Z' s" S; Y5 # ]8 |8 F$ n7 h: ~
[color=rgb(49, 124, 197) !important]6
# n; K5 ]) l9 s; m% h/ c$ I$ U ) ^- x: ^2 |: q2 }' Z* P9 `
| [color=rgb(0, 45, 122) !important]ubuntu[color=rgb(102, 102, 102) !important]@vm1[color=rgb(0, 111, 224) !important]:[color=rgb(0, 111, 224) !important]~[color=rgb(51, 51, 51) !important]$[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]sudo [color=rgb(0, 45, 122) !important]dhclient[color=rgb(0, 111, 224) !important] [color=rgb(0, 111, 224) !important]-[color=rgb(0, 0, 0) !important]v[color=rgb(0, 111, 224) !important] [color=rgb(0, 45, 122) !important]ens3[color=rgb(51, 51, 51) !important].[color=rgb(206, 0, 0) !important]102[color=rgb(0, 111, 224) !important] ! A1 J% C9 l& ]- x& E$ i9 T
[color=rgb(0, 78, 208) !important]DHCPDISCOVER [color=rgb(0, 78, 208) !important]on [color=rgb(0, 45, 122) !important]ens3[color=rgb(51, 51, 51) !important].[color=rgb(206, 0, 0) !important]102[color=rgb(0, 111, 224) !important] [color=rgb(128, 0, 128) !important]to[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]255.255.255.255[color=rgb(0, 111, 224) !important] [color=rgb(0, 0, 0) !important]port[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]67[color=rgb(0, 111, 224) !important] [color=rgb(0, 0, 0) !important]interval[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]3[color=rgb(0, 111, 224) !important] [color=rgb(51, 51, 51) !important]([color=rgb(0, 45, 122) !important]xid[color=rgb(0, 111, 224) !important]=[color=rgb(206, 0, 0) !important]0x8e2bc124[color=rgb(51, 51, 51) !important])
0 O3 I! \! k$ w# p2 w3 Z6 u8 ?[color=rgb(0, 78, 208) !important]DHCPREQUEST [color=rgb(0, 0, 0) !important]of[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]21.0.0.6[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]on [color=rgb(0, 45, 122) !important]ens3[color=rgb(51, 51, 51) !important].[color=rgb(206, 0, 0) !important]102[color=rgb(0, 111, 224) !important] [color=rgb(128, 0, 128) !important]to[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]255.255.255.255[color=rgb(0, 111, 224) !important] [color=rgb(0, 0, 0) !important]port[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]67[color=rgb(0, 111, 224) !important] [color=rgb(51, 51, 51) !important]([color=rgb(0, 45, 122) !important]xid[color=rgb(0, 111, 224) !important]=[color=rgb(206, 0, 0) !important]0x24c12b8e[color=rgb(51, 51, 51) !important])
; ~1 y& Y3 q, V[color=rgb(0, 78, 208) !important]DHCPOFFER [color=rgb(0, 0, 0) !important]of[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]21.0.0.6[color=rgb(0, 111, 224) !important] [color=rgb(0, 0, 0) !important]from[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]21.0.0.2 / R6 x, [$ r7 s: [- S6 Q
[color=rgb(0, 78, 208) !important]DHCPACK [color=rgb(0, 0, 0) !important]of[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]21.0.0.6[color=rgb(0, 111, 224) !important] [color=rgb(0, 0, 0) !important]from[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]21.0.0.2 2 q( k" D t6 H. v* ?4 P
[color=rgb(0, 78, 208) !important]bound [color=rgb(128, 0, 128) !important]to[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]21.0.0.6[color=rgb(0, 111, 224) !important] [color=rgb(0, 111, 224) !important]--[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]renewal [color=rgb(128, 0, 128) !important]in[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]42323[color=rgb(0, 111, 224) !important] [color=rgb(0, 45, 122) !important]seconds[color=rgb(51, 51, 51) !important]. # N% k, D2 |: \; _, @- x
/ [0 ]& D1 d* {8 m
|
* h' z) i1 C1 t4 \8 Q5 J9 _
1 S4 a2 T9 }! \9 B1 A6 U4 U: I可以看到,子网卡也可以通过Neutron的DHCP服务获取IP地址。
! ?* Y1 y# ~8 K4 DVLAN互通
2 i5 b4 w" R, x# A3 k在vm1内部,ping vm2. [color=rgb(51, 51, 51) !important]* \! f4 \, \2 @3 R8 }) Q
0 G: ^6 J2 X: o2 z2 z3 e. m% s
7 b7 z. Y" V7 k 8 J: Q5 r- m% q& c, k
" O7 P. j L% j2 X
4 }: Z: O3 j4 Y0 t3 Q }: V: N
8 T; r/ ]" ~* x' I, j- l" ~9 e0 z & ~0 W6 u3 f! Z" G
( a4 }, K% T* X. s+ L
, B: G' Y( x5 p1 d[color=rgb(153, 153, 153) !important]Java . O# u1 c4 ~0 \9 w6 ?
, p8 f, i% r% b
. @. L4 k1 ?0 z. Y1
0 v2 ~% x R) ?! \# |[color=rgb(49, 124, 197) !important]2
1 t$ ]# Y U0 R, \3 ' W: w$ I* R! r( P: j4 t
[color=rgb(49, 124, 197) !important]4 % @ x f$ F6 e! w/ ~7 `# z+ t- S
5
( Z9 K! u$ Q: `; T5 q
) B5 k% M% I& L* k/ u6 E | [color=rgb(0, 45, 122) !important]ubuntu[color=rgb(102, 102, 102) !important]@vm1[color=rgb(0, 111, 224) !important]:[color=rgb(0, 111, 224) !important]~[color=rgb(51, 51, 51) !important]$[color=rgb(0, 111, 224) !important] [color=rgb(0, 0, 0) !important]ping[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]21.0.0.7 - o2 z4 U, `" r) R
[color=rgb(0, 0, 0) !important]PING[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]21.0.0.7[color=rgb(0, 111, 224) !important] [color=rgb(51, 51, 51) !important]([color=rgb(206, 0, 0) !important]21.0.0.7[color=rgb(51, 51, 51) !important])[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]56[color=rgb(51, 51, 51) !important]([color=rgb(206, 0, 0) !important]84[color=rgb(51, 51, 51) !important])[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]bytes [color=rgb(0, 78, 208) !important]of [color=rgb(0, 45, 122) !important]data[color=rgb(51, 51, 51) !important].
& F. Y! X" e: ?" p[color=rgb(206, 0, 0) !important]64[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]bytes [color=rgb(0, 0, 0) !important]from[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]21.0.0.7[color=rgb(0, 111, 224) !important]:[color=rgb(0, 111, 224) !important] [color=rgb(0, 45, 122) !important]icmp_seq[color=rgb(0, 111, 224) !important]=[color=rgb(206, 0, 0) !important]1[color=rgb(0, 111, 224) !important] [color=rgb(0, 45, 122) !important]ttl[color=rgb(0, 111, 224) !important]=[color=rgb(206, 0, 0) !important]64[color=rgb(0, 111, 224) !important] [color=rgb(0, 45, 122) !important]time[color=rgb(0, 111, 224) !important]=[color=rgb(206, 0, 0) !important]10.2[color=rgb(0, 111, 224) !important] [color=rgb(0, 0, 0) !important]ms 7 v% J* c. _/ x: b i2 ?
[color=rgb(206, 0, 0) !important]64[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]bytes [color=rgb(0, 0, 0) !important]from[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]21.0.0.7[color=rgb(0, 111, 224) !important]:[color=rgb(0, 111, 224) !important] [color=rgb(0, 45, 122) !important]icmp_seq[color=rgb(0, 111, 224) !important]=[color=rgb(206, 0, 0) !important]2[color=rgb(0, 111, 224) !important] [color=rgb(0, 45, 122) !important]ttl[color=rgb(0, 111, 224) !important]=[color=rgb(206, 0, 0) !important]64[color=rgb(0, 111, 224) !important] [color=rgb(0, 45, 122) !important]time[color=rgb(0, 111, 224) !important]=[color=rgb(206, 0, 0) !important]0.979[color=rgb(0, 111, 224) !important] [color=rgb(0, 0, 0) !important]ms
1 k0 s) Y- y, I" N; @. I8 G/ R[color=rgb(206, 0, 0) !important]64[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]bytes [color=rgb(0, 0, 0) !important]from[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]21.0.0.7[color=rgb(0, 111, 224) !important]:[color=rgb(0, 111, 224) !important] [color=rgb(0, 45, 122) !important]icmp_seq[color=rgb(0, 111, 224) !important]=[color=rgb(206, 0, 0) !important]3[color=rgb(0, 111, 224) !important] [color=rgb(0, 45, 122) !important]ttl[color=rgb(0, 111, 224) !important]=[color=rgb(206, 0, 0) !important]64[color=rgb(0, 111, 224) !important] [color=rgb(0, 45, 122) !important]time[color=rgb(0, 111, 224) !important]=[color=rgb(206, 0, 0) !important]0.817[color=rgb(0, 111, 224) !important] [color=rgb(0, 45, 122) !important]ms + c# w8 p+ Y0 x5 E
6 Y. J2 T5 P5 X3 {8 f. B( w7 z0 J |
9 c; L8 e) I# u
+ `. }3 C! C- D在vm2内部,查看收到的包。前面讲过Linux VLAN Trunk的工作过程,Ethernet Frame发送到ens3.102时,已经剥离了VLAN标签。为了查看VLAN信息,所以我们这里直接监听ens3 [color=rgb(51, 51, 51) !important]
7 \! b- R6 Y3 e: d ) \* ~: l9 Q6 y) _: Q
* y& L8 O2 s% R1 D" b. _ & I$ } Y Q1 M/ u( C9 D
0 l; \+ \/ l" L8 ?5 K; c
/ d. Q2 X; _4 q- _* f6 \. L
' F9 I" w; C+ s. r
- [- C* j( c6 [3 W- Q' z$ h8 Y& f, |* l# c
: O2 M: B4 W: E7 V3 U6 a3 c[color=rgb(153, 153, 153) !important]Java 6 D* {( m- q6 |3 f |
2 j3 g o: T3 F/ Y* ]
" p+ {/ w* q; g% |- W
1 Z# V4 P/ P% d a
[color=rgb(49, 124, 197) !important]2
' p# q+ B1 X, l$ z% L3
0 S9 [( b* Z' Z$ r; P# ^
+ c0 a& m5 h* d" D P | [color=rgb(0, 45, 122) !important]ubuntu[color=rgb(102, 102, 102) !important]@vm2[color=rgb(0, 111, 224) !important]:[color=rgb(0, 111, 224) !important]~[color=rgb(51, 51, 51) !important]$[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]sudo [color=rgb(0, 45, 122) !important]tcpdump[color=rgb(0, 111, 224) !important] [color=rgb(0, 111, 224) !important]-[color=rgb(0, 78, 208) !important]nei [color=rgb(0, 78, 208) !important]ens3 [color=rgb(0, 0, 0) !important]icmp
* l; B ~" X) P7 [; b[color=rgb(206, 0, 0) !important]08[color=rgb(0, 111, 224) !important]:[color=rgb(206, 0, 0) !important]42[color=rgb(0, 111, 224) !important]:[color=rgb(206, 0, 0) !important]24.256617[color=rgb(0, 111, 224) !important] [color=rgb(0, 45, 122) !important]fa[color=rgb(0, 111, 224) !important]:[color=rgb(206, 0, 0) !important]16[color=rgb(0, 111, 224) !important]:[color=rgb(206, 0, 0) !important]3e[color=rgb(0, 111, 224) !important]:[color=rgb(206, 0, 0) !important]61[color=rgb(0, 111, 224) !important]:[color=rgb(206, 0, 0) !important]62[color=rgb(0, 111, 224) !important]:[color=rgb(0, 45, 122) !important]fa[color=rgb(0, 111, 224) !important] [color=rgb(0, 111, 224) !important]>[color=rgb(0, 111, 224) !important] [color=rgb(0, 45, 122) !important]fa[color=rgb(0, 111, 224) !important]:[color=rgb(206, 0, 0) !important]16[color=rgb(0, 111, 224) !important]:[color=rgb(206, 0, 0) !important]3e[color=rgb(0, 111, 224) !important]:[color=rgb(0, 45, 122) !important]da[color=rgb(0, 111, 224) !important]:[color=rgb(206, 0, 0) !important]61[color=rgb(0, 111, 224) !important]:[color=rgb(206, 0, 0) !important]99[color=rgb(51, 51, 51) !important],[color=rgb(0, 111, 224) !important] [color=rgb(0, 0, 0) !important]ethertype[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]802.1Q[color=rgb(0, 111, 224) !important] [color=rgb(51, 51, 51) !important]([color=rgb(206, 0, 0) !important]0x8100[color=rgb(51, 51, 51) !important])[color=rgb(51, 51, 51) !important],[color=rgb(0, 111, 224) !important] [color=rgb(0, 0, 0) !important]length[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]102[color=rgb(0, 111, 224) !important]:[color=rgb(0, 111, 224) !important] [color=rgb(0, 0, 0) !important]vlan[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]102[color=rgb(51, 51, 51) !important],[color=rgb(0, 111, 224) !important] [color=rgb(0, 0, 0) !important]p[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]0[color=rgb(51, 51, 51) !important],[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]ethertype [color=rgb(0, 45, 122) !important]IPv4[color=rgb(51, 51, 51) !important],[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]21.0.0.6[color=rgb(0, 111, 224) !important] [color=rgb(0, 111, 224) !important]>[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]21.0.0.7[color=rgb(0, 111, 224) !important]:[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]ICMP [color=rgb(0, 78, 208) !important]echo [color=rgb(0, 45, 122) !important]request[color=rgb(51, 51, 51) !important],[color=rgb(0, 111, 224) !important] [color=rgb(0, 0, 0) !important]id[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]11731[color=rgb(51, 51, 51) !important],[color=rgb(0, 111, 224) !important] [color=rgb(0, 0, 0) !important]seq[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]388[color=rgb(51, 51, 51) !important],[color=rgb(0, 111, 224) !important] [color=rgb(0, 0, 0) !important]length[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]64[color=rgb(0, 111, 224) !important]
$ F0 N$ k5 F5 P% H7 L; t[color=rgb(206, 0, 0) !important]08[color=rgb(0, 111, 224) !important]:[color=rgb(206, 0, 0) !important]42[color=rgb(0, 111, 224) !important]:[color=rgb(206, 0, 0) !important]25.258424[color=rgb(0, 111, 224) !important] [color=rgb(0, 45, 122) !important]fa[color=rgb(0, 111, 224) !important]:[color=rgb(206, 0, 0) !important]16[color=rgb(0, 111, 224) !important]:[color=rgb(206, 0, 0) !important]3e[color=rgb(0, 111, 224) !important]:[color=rgb(206, 0, 0) !important]61[color=rgb(0, 111, 224) !important]:[color=rgb(206, 0, 0) !important]62[color=rgb(0, 111, 224) !important]:[color=rgb(0, 45, 122) !important]fa[color=rgb(0, 111, 224) !important] [color=rgb(0, 111, 224) !important]>[color=rgb(0, 111, 224) !important] [color=rgb(0, 45, 122) !important]fa[color=rgb(0, 111, 224) !important]:[color=rgb(206, 0, 0) !important]16[color=rgb(0, 111, 224) !important]:[color=rgb(206, 0, 0) !important]3e[color=rgb(0, 111, 224) !important]:[color=rgb(0, 45, 122) !important]da[color=rgb(0, 111, 224) !important]:[color=rgb(206, 0, 0) !important]61[color=rgb(0, 111, 224) !important]:[color=rgb(206, 0, 0) !important]99[color=rgb(51, 51, 51) !important],[color=rgb(0, 111, 224) !important] [color=rgb(0, 0, 0) !important]ethertype[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]802.1Q[color=rgb(0, 111, 224) !important] [color=rgb(51, 51, 51) !important]([color=rgb(206, 0, 0) !important]0x8100[color=rgb(51, 51, 51) !important])[color=rgb(51, 51, 51) !important],[color=rgb(0, 111, 224) !important] [color=rgb(0, 0, 0) !important]length[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]102[color=rgb(0, 111, 224) !important]:[color=rgb(0, 111, 224) !important] [color=rgb(0, 0, 0) !important]vlan[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]102[color=rgb(51, 51, 51) !important],[color=rgb(0, 111, 224) !important] [color=rgb(0, 0, 0) !important]p[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]0[color=rgb(51, 51, 51) !important],[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]ethertype [color=rgb(0, 45, 122) !important]IPv4[color=rgb(51, 51, 51) !important],[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]21.0.0.6[color=rgb(0, 111, 224) !important] [color=rgb(0, 111, 224) !important]>[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]21.0.0.7[color=rgb(0, 111, 224) !important]:[color=rgb(0, 111, 224) !important] [color=rgb(0, 78, 208) !important]ICMP [color=rgb(0, 78, 208) !important]echo [color=rgb(0, 45, 122) !important]request[color=rgb(51, 51, 51) !important],[color=rgb(0, 111, 224) !important] [color=rgb(0, 0, 0) !important]id[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]11731[color=rgb(51, 51, 51) !important],[color=rgb(0, 111, 224) !important] [color=rgb(0, 0, 0) !important]seq[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]389[color=rgb(51, 51, 51) !important],[color=rgb(0, 111, 224) !important] [color=rgb(0, 0, 0) !important]length[color=rgb(0, 111, 224) !important] [color=rgb(206, 0, 0) !important]64
4 _* F* e0 g& ^# ^* K
$ a6 S2 k6 p. k |
) D; P$ m( P3 p9 q0 ^9 T3 c/ ` 5 h4 z' E: e' o! h W: K
可以看到,vm2收到的原始Ethernet Frame是带VLAN Tag的。 2.3 原理注:这部分内容假设你对OpenStack Neutron已经有一定的了解了。
- M# l9 f9 S* q# n/ ~虽然上面完成了VLAN aware VMs的配置和Linux VLAN Trunk的验证,甚至虚机内的subport都可以使用Neutron的DHCP服务,但是这里留下了两个问题没有解答。 - 首先,不用在vSwitch和Physical switch上打开trunk模式,就能支持带VLAN Tag的帧的传递,这中间发生了什么?
- 其次,一个传输VLAN数据的subport如何能使用定义在VXLAN网络中的DHCP服务?
8 F) W6 }% `2 f! v9 [9 }
看完Neutron VLAN aware VMs的架构,这两个问题自然就能解决。首先我们看看计算节点上的OpenVSwitch网桥。可以发现,对每个Trunk port,对应的新增了一个网桥。! \' M- R' r& k! o7 U, N) _
9 Q/ i7 h# `, t3 E- Z
在这个网桥的端口中,qvo端口是用来连接虚机的,剩下的端口中,一个是bridge对应的端口,剩下两个都是patch port。其中一个还带了VLAN Tag 102,正是我们配置的segmentation-id。patch port都是成对出现,这里的patch port peer都挂在br-int上。具体的网桥和端口的关系如下图所示:
. X- S. L8 B: ^/ q4 \
8 y3 k1 J; j% R1 D; ] [5 _8 W左上角是正常的OpenVSwitch上连接的虚机,为什么不是虚机直接到OpenVSwitch网桥?这是历史遗留问题,这里不做解释,大家只需要知道qvo是br-int上用来连接虚机的端口。再看虚线框内,上半部分与原来虚机伸出的部分相同,下半部分就是之前展示的新增的网桥。网桥向上通过qvo连接虚机。向下通过patch port pair 连接parent port,从虚机出来的不带VLAN Tag的帧,从这对patch port走到br-int。同时向下通过patch port pair 连接subport,一个subport对应一对spt-spi,注意的是每个spt都带有相应的VLAN Tag,根据OVS的特性,所有从虚机出来的,带上相应VLAN Tag的帧都会发送到相应的spt,再通过spi发送到br-int。 所以,从虚机出来的Ethernet Frame,根据所携带的VLAN Tag(或者不带VLAN Tag),在tbr网桥上,可以分配到不同的patch port,进而转发到br-int上的不同端口。也就是说,在tbr上,从虚机里一块网卡发出来的Ethernet Frame被分流了。 在br-int上,其实不知道qvo、spi,tpi有什么区别,这些端口对于br-int来说地位是一样的。这些端口分别在不同的网络中(最开始为parent port和subport分别创建了网络),br-int根据端口所在的网络,将虚机发出来的Ethernet Frame打上Local network ID(又一个VLAN ID,类似于VTEP中VLAN ID与VXLAN ID对应中的VLAN),发往br-tun。在br-tun根据Local network ID转换成VXLAN数据发送出去。 在对端,经过br-tun发送到br-int,br-int根据不同的网络,将数据发送到相应的qvo,spi,tpi。这里看spi这条线路,因为patch port的相连,数据发送到了tbr网桥,再经由qvo发向虚机。由于qvo没有自己的VLAN Tag,所以它将保留入口端口的VLAN Tag,也就是VLAN 102,最后VLAN 102的帧发送给虚机。 总结一下Ethernet Frame的处理流程。从虚机发出来的VLAN数据,在tbr网桥通过相应的patch port 对,发送到br-int。在patch port对的传递过程中,VLAN Tag由虚机内定义的VLAN ID变成了br-int内部的Local network ID。br-int将数据发送给br-tun。br-tun根据自身记录的VLAN ID与VXLAN ID的对应,将VLAN数据中VLAN Tag去除,并将剩余的Ethernet Frame封装成VXLAN数据,在VXLAN tunnel上传输。 对端收到VXLAN数据,在br-tun转换成VLAN数据,VLAN Tag是Local network ID,再发送给br-int。br-int根据Local network ID和目的MAC地址,将VLAN数据从对应的端口(spi)发出。经过patch port 对的传输,VLAN Tag由Local network ID变成了spt上的VLAN Tag,最后通过qvo发送给虚机。虚机收到还是VLAN 102的数据,但是数据在中间是通过VXLAN网络传输。 所以为什么不需要vSwitch和Physical Switch对Trunk模式进行支持?因为VLAN数据换成了VXLAN数据,传输的都不是VLAN了,自然不需要交换机配置Trunk。为什么子网卡能使用Neutron的DHCP服务,因为数据被换成了Neutron network网络数据(VXLAN),接入到Neutron network,自然就能使用Neutron network内的服务。 三、SDN中VLAN的实现Neutron在OpenVSwitch上实现的VLAN aware VMs原理在上面介绍过,不得不说,这个方案比较复杂,希望我已经说清楚了。虽然这个方案不依赖物理网络配置Trunk,但是需要创建额外的网桥和端口,对应的转换步骤也太多了。这么实现有Neutron的历史原因,也有Neutron轻度依赖OpenFlow的因素在里面。我们接下来看看在OpenFlow中,如何实现VLAN aware VMs。 VLAN aware VMs的核心思想是,用Neutron tenant network的overlay网络,来传输Linux VLAN Trunk发出来的各种VLAN数据。像上面的介绍,就是用VXLAN网络来传输虚机发出的VLAN数据,在进出虚机的时候再对VLAN Tag做相应的处理。相同的功能在OpenFlow中实现就简单的多,我们以Dragonflow项目的实现为例,具体介绍在Spec for VLAN aware VMs。只需要在网桥上添加几条OpenFlow流表,就能识别虚机发出的数据,并分发到不同的Neutron tenant network,进而通过Neutron tenant network传输。 在虚机的出口,添加下列流表: [color=rgb(51, 51, 51) !important]
: d% `$ }% j" f2 i7 x. n9 _ * L- @/ G* l4 r4 [, L
2 r+ t+ d8 L/ z* Z0 N
. ]# {0 {& \; s! p% ^! Z' {5 r/ l: o( e! n1 ~* l ^
6 |7 s1 \* ^4 M; [6 ^! ?& _ n9 G) y
l+ S/ p3 j/ N9 {. D
; n5 g1 j/ u8 m 7 I8 v$ G8 O% K: V& A3 I
[color=rgb(153, 153, 153) !important]Java 1 d K2 A6 _3 P& B" K
`, p% u4 F& C1 S, E
; V2 y3 U6 g) O- R1
" R) D6 d! L( r* E8 F/ T[color=rgb(49, 124, 197) !important]2
& g1 k2 X0 q2 b5 u, z P
n4 y9 p1 {' K3 n% r | [color=rgb(0, 45, 122) !important]table[color=rgb(0, 111, 224) !important]=[color=rgb(206, 0, 0) !important]0[color=rgb(51, 51, 51) !important],[color=rgb(0, 111, 224) !important] [color=rgb(0, 45, 122) !important]priority[color=rgb(0, 111, 224) !important]=[color=rgb(206, 0, 0) !important]150[color=rgb(51, 51, 51) !important],[color=rgb(0, 45, 122) !important]in_port[color=rgb(0, 111, 224) !important]=[color=rgb(206, 0, 0) !important]183[color=rgb(51, 51, 51) !important],[color=rgb(0, 45, 122) !important]vlan[color=rgb(51, 51, 51) !important],[color=rgb(0, 45, 122) !important]vlan_tag[color=rgb(0, 111, 224) !important]=[color=rgb(206, 0, 0) !important]102[color=rgb(0, 111, 224) !important] [color=rgb(0, 45, 122) !important]actions[color=rgb(0, 111, 224) !important]=[color=rgb(0, 45, 122) !important]strip_vlan[color=rgb(51, 51, 51) !important],[color=rgb(0, 45, 122) !important]load[color=rgb(0, 111, 224) !important]:[color=rgb(206, 0, 0) !important]0x168[color=rgb(0, 111, 224) !important]->[color=rgb(0, 45, 122) !important]NXM_NX_REG6[color=rgb(51, 51, 51) !important][[color=rgb(51, 51, 51) !important][color=rgb(51, 51, 51) !important],[color=rgb(0, 45, 122) !important]load[color=rgb(0, 111, 224) !important]:[color=rgb(206, 0, 0) !important]0x2[color=rgb(0, 111, 224) !important]->[color=rgb(0, 45, 122) !important]OXM_OF_METADATA[color=rgb(51, 51, 51) !important][[color=rgb(51, 51, 51) !important][color=rgb(51, 51, 51) !important],[color=rgb(0, 78, 208) !important]resubmit[color=rgb(51, 51, 51) !important]([color=rgb(51, 51, 51) !important],[color=rgb(206, 0, 0) !important]5[color=rgb(51, 51, 51) !important])[color=rgb(0, 111, 224) !important] $ S# @1 ] E. c4 m0 a7 Y9 F5 _
[color=rgb(0, 45, 122) !important]table[color=rgb(0, 111, 224) !important]=[color=rgb(206, 0, 0) !important]0[color=rgb(51, 51, 51) !important],[color=rgb(0, 111, 224) !important] [color=rgb(0, 45, 122) !important]priority[color=rgb(0, 111, 224) !important]=[color=rgb(206, 0, 0) !important]100[color=rgb(51, 51, 51) !important],[color=rgb(0, 45, 122) !important]in_port[color=rgb(0, 111, 224) !important]=[color=rgb(206, 0, 0) !important]183[color=rgb(0, 111, 224) !important] [color=rgb(0, 45, 122) !important]actions[color=rgb(0, 111, 224) !important]=[color=rgb(0, 45, 122) !important]load[color=rgb(0, 111, 224) !important]:[color=rgb(206, 0, 0) !important]0x166[color=rgb(0, 111, 224) !important]->[color=rgb(0, 45, 122) !important]NXM_NX_REG6[color=rgb(51, 51, 51) !important][[color=rgb(51, 51, 51) !important][color=rgb(51, 51, 51) !important],[color=rgb(0, 45, 122) !important]load[color=rgb(0, 111, 224) !important]:[color=rgb(206, 0, 0) !important]0x1[color=rgb(0, 111, 224) !important]->[color=rgb(0, 45, 122) !important]OXM_OF_METADATA[color=rgb(51, 51, 51) !important][[color=rgb(51, 51, 51) !important][color=rgb(51, 51, 51) !important],[color=rgb(0, 78, 208) !important]resubmit[color=rgb(51, 51, 51) !important]([color=rgb(51, 51, 51) !important],[color=rgb(206, 0, 0) !important]5[color=rgb(51, 51, 51) !important]) * W8 ?+ R' S$ Y/ z
: |9 C: j3 x$ e" G: K( j5 D$ ~
|
# h: l) Y5 ^2 b: f/ n3 a) y% d" ]
. b4 M$ b: ~& Y0 q; w5 q这里的REG6表明入口端口,METADATA用来识别网络,可见,在table0就已经完成了将虚机中一块网卡发出的Ethernet Frame根据VLAN Tag分成不同的通道,并识别相应的网络。之后的传输不需要区分究竟是不是子网卡的数据,就是当成普通的overlay tenant network传输。 在虚机的入口,添加下列流表: [color=rgb(51, 51, 51) !important]
+ F @1 A3 g% M& k6 Y' ~4 n7 i H
8 `) ], E. R' s% [5 i5 v* q! n3 p8 I+ J% m
/ ?3 B+ [, n' w
* ]7 l: I+ x6 C, Z) W
# y/ u: b+ X5 T9 k' a) m* f( `) L5 n) z% s: g3 }* W; z
- v; z) Q7 l0 o% A3 q0 o6 p3 w/ ]4 {4 u' o
& F$ {8 ~+ U5 ~) y6 J+ G, x4 n[color=rgb(153, 153, 153) !important]Java
3 z( \1 s& K9 x3 o* S9 ^
+ ^0 z1 r# u1 q4 l: i+ |6 g, N! J0 }3 N, T9 v" A7 g! H- |
1 " m/ |9 X$ a" O) Z6 S0 D7 T5 t
[color=rgb(49, 124, 197) !important]2 " Y3 t# V) p; _1 q( y! X
+ v! N( a7 B! Y+ i% |
| [color=rgb(0, 45, 122) !important]table[color=rgb(0, 111, 224) !important]=[color=rgb(206, 0, 0) !important]115[color=rgb(51, 51, 51) !important],[color=rgb(0, 111, 224) !important] [color=rgb(0, 45, 122) !important]priority[color=rgb(0, 111, 224) !important]=[color=rgb(206, 0, 0) !important]100[color=rgb(51, 51, 51) !important],[color=rgb(0, 45, 122) !important]reg7[color=rgb(0, 111, 224) !important]=[color=rgb(206, 0, 0) !important]0x168[color=rgb(0, 111, 224) !important] [color=rgb(0, 45, 122) !important]actions[color=rgb(0, 111, 224) !important]=[color=rgb(0, 45, 122) !important]mod_vlan_vid[color=rgb(0, 111, 224) !important]:[color=rgb(0, 45, 122) !important]vlan_vid[color=rgb(0, 111, 224) !important]:[color=rgb(206, 0, 0) !important]0x10066[color=rgb(51, 51, 51) !important],[color=rgb(0, 45, 122) !important]output[color=rgb(0, 111, 224) !important]:[color=rgb(206, 0, 0) !important]183 ) p- y& e2 E5 V# s; x5 X( e
[color=rgb(0, 45, 122) !important]table[color=rgb(0, 111, 224) !important]=[color=rgb(206, 0, 0) !important]115[color=rgb(51, 51, 51) !important],[color=rgb(0, 111, 224) !important] [color=rgb(0, 45, 122) !important]priority[color=rgb(0, 111, 224) !important]=[color=rgb(206, 0, 0) !important]100[color=rgb(51, 51, 51) !important],[color=rgb(0, 45, 122) !important]reg7[color=rgb(0, 111, 224) !important]=[color=rgb(206, 0, 0) !important]0x166[color=rgb(0, 111, 224) !important] [color=rgb(0, 45, 122) !important]actions[color=rgb(0, 111, 224) !important]=[color=rgb(0, 45, 122) !important]output[color=rgb(0, 111, 224) !important]:[color=rgb(206, 0, 0) !important]183
$ B( X$ W( i, \0 c& U( R
/ i) i+ A+ B: W" ^, b7 M) y+ ^ |
( j; Z# k6 t) c ' e# o+ D! H- c6 p5 Q
“mod_vlan_vid:vlan_vid:0x10066”就是打上VLAN Tag102,可以看出不同网络的数据,打上不同的VLAN Tag(对于parent port不打VLAN Tag)发向了同一个端口183(虚机网卡)。( V* x; n. \( |2 m
没有多余的网桥,没有网桥上换来换去的VLAN ID,仅仅是在入口和出口处去除VLAN Tag和打上VLAN Tag,几条流表就实现了所有的功能。简单的实现一般意味着更高的效率和更少的错误,因此使用SDN方式实现VLAN aware VMs更具有优势。 四、VLAN Trunk在NFV中的应用最后我们再看看VLAN Trunk在NFV中的应用吧,这个在最开头一些简单的介绍,这里来说个用例。一个多路复用设备,需要连接多个子设备,子设备的数目是不确定的,且有可能变化,并且要求子设备间网络是隔离的。当然,我也可以给多路复用设备配置多块网卡,但是由于子设备数目不确定,网卡数目是不确定的。这个时候可以将多路复用设备的一块Ethernet网卡配置成VLAN Trunk port,在之上创建相应的subport。子设备上的网卡也配置成VLAN Trunk port,并创建对应的subport。由于配置的VLAN不一样,不同子设备之间的网络是隔离的。并且多路复用设备的subport是可以动态删减的,这满足了子设备数据是不确定的要求。具体如下图所示:+ o0 l/ o, o. G4 L

* w5 T' {; u! V V+ t不论是VLAN Transparency还是VLAN aware VMs,都是为了使得OpenStack中的虚机能够使用Linux VLAN Trunk功能。VLAN Transparency依赖vSwitch和物理交换机的配置,不说实际物理交换机的复杂性,单就是vSwitch也不一定支持Trunk模式。VLAN aware VMs通过一系列的转换,摆脱了对vSwitch和物理交换机配置的依赖,走在网线上的数据甚至都可以不是VLAN数据,这比VLAN Transparency进了一步。而通过SDN实现VLAN aware VMs可以大大简化实现过程,又更进了一步。 |