漫步云中网络

在生产环境中,云中的网络通常被划分为公共网络、管理网络和服务网络。本文首先通过三个小试验向您介绍了如何通过 TAP/TUN、NAT、Linux Bridge、VLAN 等技术实现云中网络的一般原理。有了这些基础,相信您会对接下来介绍的一个具体的 OpenStack 云的示例网络配置倍感亲切。同理,这些基础也将助您在其他云中网络中轻松漫步。阅读本文前,最好能先了解以下的知识:

  • 了解 OpenStack 将有助于对本文的理解。本文讲解的是 Linux 虚拟网络中的一般原理方法 , 虽不仅限于应用在 OpenStack 之中 , 但本文的实验是以 OpenStack 为基础的。OpenStack 是一个开源的 IaaS 云 , 您可以从 devstack 脚本 ( http://devstack.org/) 开始熟悉它。
  • 了解 QEMU 也将有助于对本文的理解。QEMU 是一种支持多种 CPU 的机器模拟器 , 本文采用 QEMU 来创建虚拟机验证本文中的试验。

什么是云?

什么是云?我的理解是,为多租户提供各层次上的服务(如操作系统层、中间件层、应用软件层等)的可动态水平扩展的服务器集群称之为云。所以云具有大规模、高可扩展性、按需服务、自动化、节能环保、高可靠性等特点。下图1从软件堆栈视角勾画了云的架构:

图 1. 云的架构

图 1. 云的架构

  • IaaS, Infrastructure as a Service,基础设施即服务:您可以简单理解为将可伸缩的操作系统(虚机或实机)实例作为基础设施服务卖给多租户,然后按需计算费用。当然,将操作系统作为基础设施服务只是 IaaS 中的一种,且是最主要的一种,我怕大家概念混淆所以就只重点提了这种。实际上,只要是基础设施提供服务了从概念上讲都应该叫 IaaS,比如说关系型数据库,如果是集群部署的话,它也是基础设施提供服务了,也应该叫 IaaS。这类产品如 IBM 的 Smart Cloud Entry,如开源的 OpenStack。
  • PaaS, Platform as a Service, 平台即服务:您可以简单理解为将可伸缩的中间件资源作为平台服务卖给多租户,然后按需计算费用。举个例子,如果 SaaS 应用程序的并发瞬间加大的话,PaaS 可以自动实时地启动一个由 IaaS 提供的操作系统实例,然后自动在它上面部署中间件应用服务器(如 IBM 的 WebSphere),最后再部署一套该 SaaS 应用实例,并自动将它们纳入到负载均衡体系之中,从而实现平台服务的自动伸缩,这就是 PaaS。这类产品如 IBM 的 IWD,如 Google 的 App Engine。
  • SaaS, Software as a Service, 软件即服务:您可以简单理解为可伸缩的分布式软件作为软件服务为用户提供某种在线服务,如视频服务,地图服务等。
  • XaaS, X as a Server, 一切即服务:只要是给多租户按需提供服务都可以叫 XaaS, 像在 OpenStack 中,将网络部分代码单独抽出来组成 Quantum 工程,就可以叫网络即服务(NaaS, Network as a Service);像使用 xCat 自动部署裸机可以叫裸机即服务(MaaS, Bare-metal as a Service)。

什么是云中网络?

在传统的数据中心中,每个网口对应唯一一个物理机;有了云,一台物理网卡可能会承载多个虚拟网卡。物理网卡与虚拟网卡之间的关系无外乎就是下列三种情况:

  1. 一对一,一个物理网卡对应对一个虚拟网卡,是下面一对多情况的一种特例
  2. 一对多,一个物理网卡对应多个虚拟网卡,是本文要介绍的情况
  3. 多对一,多个物理网对应一个虚拟网卡,即我们常说的 Bonding,用作负载均衡
图 2. 虚拟网络的主要内容

图 2. 虚拟网络的主要内容上图 2 显示了虚拟网络的主要内容:

  1. 目前,对网络的虚拟化主要集中在第 2 层和第 3 层
  2. 在 Linux 中,第 2 层通常使用 TAP 设备来实现虚拟网卡,使用 Linux Bridge 来实现虚拟交换机
  3. 在 Linux 中,第 3 层通常是基于 Iptable 的 NAT,路由及转发
  4. 对于网络隔离,可以采用传统的基于 802.1Q 协议的 VLAN 技术,但这受限于 VLAN ID 大小范围的限制,并且需要手动地在各物理交换机上配置 VLAN;也可以采用虚拟交换机软件,如 Openvswitch,它可以自动创建 GRE 隧道来避免手动去为物理交换机配置 VLAN。

下面将结合一个生产环境中的网络实例来讲解如何实现一个虚拟网络。

云中网络实验

在生产环境中,按通用做法一般将云中网络划分为三大部分,公共网络、管理&存储网络、服务网络。

公共网络:用于云向外部租户提供 API 调用或者访问

管理网络:用于云中各物理机之间的通信

存储网络:用于 iSCSI 服务端与客户端之间的流量,一般与管理网络同

服务网络:虚机内部使用的网络

为了将上述网络的实现原理讲清楚,我们选择了两台物理机做实验,并将采用 NAT、Linux Bridge、VLAN 技术分步实现一个典型的 OpenStack 云的网络拓扑。当然,这种网络的原理是通用的,并不仅限于 OpenStack 云。

  1. 台式机 (node1), 双有线网卡, 将作为控制节点、存储节点及一个计算节点
  2. 笔记本 (node2),一有线网卡,将作为一个计算节点
  3. 路由器,家中 ADSL 宽带出口
  4. 交换机 , 用于连接各物理机

值得一提的是,如果采用了 VLAN 技术进行网络隔离,且想要两台物理机上的虚机能够互访的话,交换机必须是支持 VLAN 的,且需要手动将交换机相应的端口配置成 Trunk 模式。因为我没有支持 VLAN 的物理交换机,在本实验中,我是采用直连线直接连接两台实验机器的。

下图 3 显示了实验网络拓扑:

图 3. OpenStack 实验网络拓扑

OpenStack 实验网络拓扑公共网络:192.168.99.0/24 网段,外网用户通过公共网络上提供的服务来访问云。注意:在实际的生产环境中,公共网络一般采用外网 IP,因为我没有外网 IP,所以用 192.168.99.0 网段模拟。将台式机的一有线网卡 eth1 与 TP-Link 路由器相连即可。

管理&存储网络:172.16.99.0/24 网段,管理网络用于 OpenStack 各组件以及 DB、MQ 之间进行通信;存储网络用于存储节点和需要使用外部存储的计算节点之间的通信。将台式机的另一有线网卡 eth0 和笔记本电脑的有线网卡 eth0 连接到交换机即可。

服务网络:10.0.0.0/8 网段,用于虚机内部。

两个节点的基本网络配置如下:

清单 1. node1 的基本网络配置
root@node1:/home/hua# cat /etc/network/interfaces 
auto lo 
iface lo inet loopback 
auto eth1 
iface eth1 inet dhcp 
up iptables -t nat -A POSTROUTING -s 172.16.99.0/24 -o eth1 -j MASQUERADE 
auto eth0 
iface eth0 inet static 
address 172.16.99.108 
netmask 255.255.255.0 
network 172.16.99.0 
broadcast 172.16.99.255

清单 2. node2 的基本网络配置

cat /etc/sysconfig/network-scripts/ifcfg-eth0

DEVICE=eth0 
HWADDR=00:21:86:94:63:27 
ONBOOT=yes 
BOOTPROTO=static 
USERCTL=yes 
PEERDNS=yes 
IPV6INIT=no 
NM_CONTROLLED=yes 
TYPE=Ethernet 
NETMASK=255.255.255.0 
IPADDR=172.16.99.109 
NETWORK=172.16.99.0 
GATEWAY=172.16.99.108 
DNS1=202.106.195.68 
DNS2=202.106.46.151

我虽然只用了两台物理机来模拟实际生产环境的部署模型, 但文中的这种部署结构是典型的,如果是大规模部署的话,只需要将控制节点上的每一个进程(如 DB、MQ、glance、keystone、nova-api、nova-schedule、nova-network 等)分布部署在每一台物理机即可。想要进一步的 HA 的话,可以:

  • 将 DB 配置成集群模式
  • 将 MQ 配置成集群模式
  • 采用 multi-host 模式,将 nova-network 同时安装在计算节点 (nova-compute) 上
  • 将 nova-api、nova-schedule 这些无状态的服务也同时部署在计算节点上,再加上负载均衡器分发负载
  • 采用多网卡做 Bonding

NAT

node2 可以通过 NAT 方式访问外网,数据流向如下:

  1. node2 中需设置网关指向 node1 的 eth0,例:
     GATEWAY=172.16.99.108
  2. 在 node1 中打开 ipv4 转发功能,这样,node1 会相当于一台路由器,在 eth0 收到来自 node2 的数据之后,会将数据包转发到其他网卡 eth1,
     sysctl -w net.ipv4.ip_forward=1
  3. 在 node1 上设置 NAT 规则,这样,从 node2(172.16.99.0/24 网段)发出的数据包看来起就像从 node1 的 eth1 发出的一样:
     iptables -t nat -A POSTROUTING -s 172.16.99.0/24 -o eth1 -j MASQUERADE

Linux Bridge

网桥 ( Bridge ) 工作在二层,了解链路层协议,按帧转发数据。就是交我们常说的交换机,所以连接到网桥的设备处于同一网段。

图 4. 网桥示例

图 4. 网桥示例上图 4 显示了 node1 网桥中的 VM1 与 node2 网桥中的 VM2 是如何通信的。在 openstack 中,这是典型的 multi-host 模式,即每一个计算节点均部署了网络服务来提供网关服务。Linux Bridge 充当了交换机的功能,而将 sysctl -w net.ipv4.ip_forward 设置为 1 也相当于 node1 同时充当了一个路由器(路由器的实质就是一个具有多个网卡的机器,因为它的多网卡同时具有这些不同网段的 IP 地址,所以它能将一个网络的流量路由转发到另一个网络)。

网桥,交换机,是用来连接两个 LAN 的。 是根据 MAC 与端口的映射进行转发的,而在虚机的网卡都是知道的,若从转发数据库知道目的 MAC 地址,以太网帧就只会正确的网桥端口传输,否则,就会扩散到网桥设备的所有端口。

因为网桥工作在第二层,所以 eth0.1, tap0, tap1 这些网卡均不需要设置 IP(因为对于上层路由器来说,它们是同一个子网,只需要将 IP 设置在 br1 上即可)。同时, 对 Linux 而言,网桥是虚拟设备,因此,除非将一个或多个真实设备绑定到网桥设备上,否则它就无法接收或传输任何东西。所以需要将一个真实设备(如 eth0)或者真实设备的 vlan 接口(如 eth0.1) 加入到网桥。对于前一种情况,将 eth0 加入到网桥之后,eth0 便不再具有 IP,这时候它与 tap0 这些虚拟网卡均通过 br1 处于 10.0.1.0/24 网络,当然我们也可以为网桥 br1 设置一个别名让它也具有 172.16.99.0/24 网管网段的 IP 地址。)

下面,我们来实现这个示例网桥,在 node1 与 node2 上分别执行下述脚本(对重要命令的描述请参见注释):

清单 3. node1 与 node2 的 Linux Bridge 配置脚本
 #!/bin/sh 
 TAP=tap0 
 BRIDGE=br1 
 IFACE=eth0 
 MANAGE_IP=172.16.99.108 
 SERVICE_IP=10.0.1.1 
 GATEWAY=10.0.1.1 
 BROADCAST=10.0.1.255 
 # 设置物理网卡为混杂模式
 ifdown $IFACE 
 ifconfig $IFACE 0.0.0.0 promisc up 
 # 创建网桥,并物理网卡加入网桥,同时设置网桥的 IP 为服务网络网段
 brctl addbr $BRIDGE 
 brctl addif $BRIDGE $IFACE 
 brctl stp $BRIDGE on 
 ifconfig $BRIDGE $SERVICE_IP netmask 255.255.255.0 broadcast $BROADCAST 
 route add default gw $GATEWAY 
 # 在网桥上设置多 IP,让它同时具有管理网段的 IP 
 ifconfig ${BRIDGE}:0 $MANAGE_IP netmask 255.255.255.0 broadcast 172.16.99.255

注意,上述黑体的一句在 node2 中需要作相应修改,其余不变,如下:

 MANAGE_IP=172.16.99.109

VLAN

图 4 同样适用于 VLAN 网络,下面我们来实现它。在 node1 与 node2 上分别执行下述脚本:

清单 4. node1 与 node2 的 VLAN 配置脚本
MAC=c8:3a:35:d7:86:da 
 IP=10.0.1.1/24 
 ip link add link eth1 name eth1.1 type vlan id 1 
 ip link set eth1.1 up 
 brctl addbr br1 
 brctl setfd br1 0 
 brctl stp br1 on 
 ip link set br1 address $MAC 
 ip link set br1 up 
 brctl addif br1 eth1.1 
 ip addr add $IP dev br1

注意,上述黑体的一句在 node2 中需要作相应修改,其余不变,如下:

 MAC= c8:3a:35:d7:86:db

测试

我们采用 QEMU 创建虚拟机来进行测试,其中网络部分的配置为:

   <interface type='bridge'>
     <mac address='52:54:00:00:01:89'/>
     <source bridge='br1'/>
     <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
   </interface>

我们使用一个现成的镜像,下载地址:

curl http://wiki.qemu.org/download/linux-0.2.img.bz2 -o /bak/kvmimages/linux-0.2.img

在 node1 与 node2 上分别用下列配置定义两个虚机,注意,下面打粗体的部分(<mac address='52:54:00:00:01:89'/>)在两个节点中请设置不一样的值。

cat /etc/libvirt/qemu/test.xml

清单 5. node1 与 node2 的虚机定义文件
 <domain type='qemu'> 
 <name>VM1</name>
 <uuid></uuid> 
 <memory>393216</memory> 
 <currentMemory>393216</currentMemory> 
 <vcpu>1</vcpu> 
 <os> 
 <type arch='i686' machine='pc-1.0'>hvm</type> 
 <boot dev='hd'/> 
 </os> 
 <features> 
 <acpi/> 
 </features> 
 <clock offset='utc'/> 
 <on_poweroff>destroy</on_poweroff> 
 <on_reboot>restart</on_reboot> 
 <on_crash>destroy</on_crash> 
 <devices> 
 <emulator>/usr/bin/qemu-system-i386</emulator> 
 <disk type='block' device='disk'> 
 <driver name='qemu' type='raw'/> 
 <source dev='/bak/kvmimages/linux-0.2.img'/> 
 <target dev='hda' bus='ide'/> 
 <address type='drive' controller='0' bus='0' unit='0'/> 
 </disk> 
 <controller type='ide' index='0'> 
 <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> 
 </controller> 
 <interface type='bridge'> 
 <mac address='52:54:00:00:01:89'/> 
<source bridge='br1'/> 
 <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> 
 </interface> 
 <input type='tablet' bus='usb'/> 
 <input type='mouse' bus='ps2'/> 
 <graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1'> 
 <listen type='address' address='127.0.0.1'/> 
 </graphics> 
 <video> 
 <model type='cirrus' vram='9216' heads='1'/> 
 <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> 
 </video> 
 <memballoon model='virtio'> 
 <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> 
 </memballoon> 
 </devices> 
 </domain>

然后用上述配置创建虚机(virsh define /etc/libvirt/qemu/test.xml ),接着启动虚机( virsh start test ),最后设置虚机的 IP 和默认网关, 如下:

VM1:

ifconfig eth0 10.0.1.2 netmask 255.255.255.0 broadcast 10.0.1.255
route add default gw 10.0.1.1

VM3:

ifconfig eth0 10.0.1.3 netmask 255.255.255.0 broadcast 10.0.1.255
route add default gw 10.0.1.1

这时候在一虚机上 ping 另一虚机 , 如果能够 ping 通,成功。若想要 ping 外网的话,还需在 /etc/resolv.conf 文件中添加域名,如下图 5 所示:

图 5. 验证实验是否成功

图 5. 验证实验是否成功

OpenStack 云中网络拓扑配置示例

在掌握了上述基本原理之后,应该不难理解下面 OpenStack 云中的网络拓扑。

在 OpenStack 中,目前存在着 nova-network 与 quantum 两种网络组件。nova-network 仅支持下列三种网络拓扑:

  • FlatManager, 不支持 VLAN,也不支持 DHCP 的扁平网络
  • FlatDHCPManager,不支持 VLAN,但支持 DHCP 的扁平网络
  • VlanManager,支持 VLAN,也支持 DHCP 的 VLAN 隔离网络

如今 nova-network 的代码已经全部挪到了 Quantum 工程中,但在网络拓扑方面,二者的原理是一致的,所以下面只给出一个典型的 nova-network 的网络配置,有了上面的基础,现在看这段配置是否会感到很亲切呢?

清单 6. /etc/nova/nova.conf 中的网络配置示例
 ##### nova-network ##### 
 network_manager=nova.network.manager.VlanManager 
 public_interface=eth1 
 vlan_interface=eth0 
 network_host=node1 
 fixed_range=10.0.0.0/8 
 network_size=1024 
 dhcpbridge_flagfile=/etc/nova/nova.conf 
 dhcpbridge=/usr/bin/nova-dhcpbridge 
 force_dhcp_release=True 
 fixed_ip_disassociate_timeout=30 
 my_ip=172.16.99.108 
 routing_source_ip=192.168.99.108

相关参数说明如下:

  • network_manager,目前支持 VlanManager、FlatManager、FlatDHCPManager 三种拓扑
  • public_interface, 接外网的物理网卡 , floating ip 功能需要用到它
  • valn_interface, 用于划分 VLAN 的物理网卡
  • fixed_range, 服务网络,即虚机内部所用的网络地址
  • my_ip,管理网络,用于安装 Openstack 组件的物理机之间的通信。例如:本实验中的控制节点同时具有外网网络地址 192.168.99.108 与管理网络地址 172.16.99.108,另一计算节点的管理网络地址为 172.16.99.109,所以 my_ip 应该设置为 172.16.99.108
  • routing_source_ip, NAT 映射后的公共网络 IP,设置了此参数,会自动执行 NAT 命令:
    iptables -t nat -A POSTROUTING -s 172.16.99.0/24 -o eth1 -j SNAT --to 192.168.99.108

显然,如果没有区分公共网络与管理网络,即它们处于同一网段的话,并不需要配置 my_ip 及 routing_source_ip 两个参数。

结论

云中网络一般被划分为公共网络、管理网络 & 存储网络与服务网络三大类。虚拟网络拓扑一般有 NAT、Bridge、VLAN 三种情形。我们手工一步一步地通过 NAT、Bridge、VLAN 三个试验简单实现了一个上述典型的云中网络。原理都是相通的,您再看 OpenStack 云中网络或才其他云的网络时都会倍感亲切。

---------------------

本文作为《漫步云中网络》的姊妹篇,在它讲述 L2-L3 层网络技术原理的基础之上,继续向大家讲述最新的 Neutron 背后所依赖的 L2-L7 层网络技术内幕,特别是这些复杂的网络技术的来龙去脉,尽量深入浅出地用浅显易懂的语言从纯技术角度切中这些技术的本质。帮您在进入研究 Neutron 细节之前就清楚知道 Neutron 是什么、有什么、为什么有,这样您在研究这些复杂网络技术时始终清楚定位不致于迷失方向。本文适合希望迅速了解 Neutron 全部特性的架构师,适合希望研究 Neutron 代码的程序员以及希望运行 Neutron 的测试人员,也适合想了解基础网络内幕知识的读者。本文不会讲解每一种网络技术的细节,也不会讲解 Neutron 网络的实现细节,而是高度概括这些基础网络技术的技术本质,试图帮您在这些网络技术和 Neutron 之间建立更高级别的联系,让大家举重若轻,全局系统把握 Neutron。所以阅读本文前,了解以下知识将有助于本文的理解:

  • 了解 OSI 七层模型,了解基本的 L2 层帧转发、L3 层路由转发等网络基础知识。
  • 了解 Neutron 网络或者其他任何云网络也将有助于本文的理解。

Neutron 是什么?

一句话描述,Neutron 是 OpenStack 的一个子模块,它的实质是一个定义良好的框架用来驱动 L2-L7 层不同的底层网络技术来为第三方应用独立地提供租户隔离的虚拟网络服务。

上面的定义只是笔者对 Neutron 长期以来一个最直观的感受,仁者见仁,智者见智,相信您在读完本文后,对于“Neutron 是什么”这个问题会有自己的看法。

笔者之前在 developworks 上曾发表过一篇文章,《漫步云中网络》,在那篇文章中,笔者也没有直接具体讲 Quantum HOWTO 的问题(目前 Quantum 因为与一家公司重名,所以已更名为 Neturon),而是描述了 Qauntum 网络背后的一般原理,读者至少可以从那篇文章获取如下知识:

  • 知道 Linux 下实现虚拟网卡一般使用 TAP/TUN 技术。一个 TAP 设备就是 Linux 下的一个进程,两个虚机通过虚拟网卡的通信,实际上就是 Linux 中两个进程间的通信。所以很多 Hypervisor 为了提升同一物理机中的两台虚机之间的网络 IO 性能采用 DMA(直接内存访问)技术也就毫不奇怪了。
  • 知道在 L2 层,Linux 网桥是虚拟交换机的一种实现,知道无论是虚拟交换机还是物理交换机,原理都是一样的。知道 L2 层用于使用 VLAN 来做物理隔离。知道 FLAT 网络和 VLAN 网络的根本区别。
  • 知道在 L3 层如何通过 ipv4 forward 功能进行静态路由转发,知道如何使用 iptables 的 SNAT 和 DNAT 规则实现内网中的虚机访问外网和外网访问内网上的虚机(也就是所谓的浮动 IP)。

在我写第一季的时候,Quantum 只实现了 L2,L3 两层,所以在《漫步云中网络》一文也就只涉及了 L2、L3 两层背后的网络原理知识。但是现在 Neutron 在 L2 和 L3 层上实现了更多的网络技术,同时在 L4-L7 层也有更多的动作,所以有必要出第二季对整个 L2-L7 层的网络进行一个全面的疏理。本季中也会概括 L2、L3 的理论知识,但不会像第一季中那么详细,大家也可以结合第一季进行学习。所以,本文的主要内容有:

  • L2 层:交换机的原理;为什么会出现 VLAN;Neutron 中 FLAT 与 VLAN 的区别;
  • L3 层:Linux 上实现静态路由的技术(namespace + ipv4 forward + iptables);动态路由;Neutron 用 L3 层的 GRE 遂道技术克服 VLAN 大小的限制;
  • 利用 L3 层扩展 L2 层的遂道技术:VXLAN; NVGRE;
  • 利用 L2 层扩展 L3 层的标签技术:MPLS;
  • 区别于传统路由转发的流转发技术:OpenFlow 以及 SDN 的实质;
  • L4-L7 层:如 LBaaS;FWaaS; VPNaaS; NATaaS

OSI 七层模型

提到网络不得不提到 OSI 七层模型,从上到下,OSI 分为七层:

  • L7,应用层
  • L6,表示层
  • L5,会话层
  • L4,运输层
  • L3,网络层
  • L2,数据链路层
  • L1,物理层

对于 OSI 七层模型至少得知道下列常识:

  • L2 层主要通过 MAC 地址进行帧转发
  • L3 层主要通过 IP 地址进行包转发
  • L4 层再结合端口 PORT 来唯一标志一个应用程序
  • 协议是通信双方对数据的一个理解,例如在 L7 层有我们常用的协议 HTTP 协议,在 HTTP 协议上传输的是通信双方都理解的 HTML 数据;在 L4 层有两大重要协议,无连接的 UDP 和面向连接的 TCP。可靠传输可以通过 TCP 协议来实现,对于下面的 L2,L3 层并不需要实现可靠传输机制,像 L2 层,传输数据帧的过程中出了错误简单丢弃就行,上层的 TCP 自然会控制它重传。socket 不是协议,只是 L4 层传输数据的一个接口定义。
  • 当网卡接收到数据之后,硬件网卡会给 CPU 发中断,CPU 在指令周期内指示操作系统软件从网卡缓冲区取走数据,然后操作系统将数据交给 TCP/IP 栈来处理,到了 L2 层,解析 L2 层数据帧头中的 MAC 地址来决定 L2 中的转发,如需 3 层转发就交给上面的 L3 层解析出数据包头中的 IP 地址来决定 L3 中的转发,依此类推。

L1

L1 是物理层,主要是涉及硬件的一些电气特性,与偏软件的 Neutron 虚拟网络从知识脉络上关系甚少,不展开。

L2

FLAT

L2 数据链路层通过交换机设备进行帧转发。交换机在接收到帧之后(L2 层叫帧,L3 层叫包)先解析出帧头中的 MAC 地址,再在转发表中查找是否有对应 MAC 地址的端口,有的话就从相应端口转发出去。没有,就洪泛(专业术语,即将帧转发到交换机的所有端口),每个端口上的计算机都检查帧头中的 MAC 地址是否与本机网卡的 MAC 地址一致,一致的话就接收数据帧,不一致就直接丢弃。而转发表是通过自学习自动建立的。

这里引出一个重要概念,混杂模式。默认情况下计算机只接收和本机 MAC 地址一致的数据帧,不一致就丢弃,如果要求计算机接受所有帧的话,就要设置网卡为混杂模式(ifconfig eth0 0.0.0.0 promisc up)。所以在虚拟网桥中,如果希望虚机和外部通讯,必须打开桥接到虚拟网桥中物理网卡的混杂模式特性。

VLAN

FLAT 中的洪泛,经常会在一个局域网内产生大量的广播,这也就是所谓的“广播风暴”。为了隔离广播风暴,引入了 VLAN 的概念。即为交换机的每一个端口设置一个 1-4094 的数字,交换机根据 MAC 地址进行转发的同时也要结合 VLAN 号这个数字,不同的话也要丢弃。这样就实现了 L2 层数据帧的物理隔离,避免了广播风暴。

在 Neutron 中,我们知道,截止到笔者写这篇文章之时已经实现了 FLAT、VLAN、GRE、VXLAN 四种网络拓扑。那么如何区分 FLAT 和 VLAN 呢?很简单,结合 VLAN 号和 MAC 地址进行转发的是 VLAN 模式,只根据 MAC 地址进行转发的是 FLAT 模式。

VLAN 的缺点与大 L2 层技术

实际上,遂道技术并不能完全归类于 L2 层。因为有基于 L2 层的遂道协议,例如 PPTP 和 L2TP 等;也有基于 L3 层的遂道,如 GRE、VXLAN、NVGRE 等;但是这些遂道从技术原理上讲差不多,所以笔者将这些技术作为“大 L2 层”放在一块来描述,但希望读者不要误解。

本文只将着重讲 Neutron 中用到的 GRE 和 VXLAN 技术。

L3 层的 GRE 遂道

VLAN 技术能有效隔离广播域,但同时有很多缺点:

  • 要求穿越的所有物理交换机都配置允许带有某个 VLAN 号的数据帧通过,因为物理交换机通常只提供 CLI 命令,不提供远程接口可编程调用,所以都需要手工配置它,容易出错且工作量巨大,纯粹的体力劳动,影响了大规模部署。
  • VLAN 号只能是 1-4094 中的一个数字,对于小规模的私有云可能不是个问题,但对于租户众多的公有云,可选择的 VLAN 号的范围是不是少了点呢?

为了克服上面的缺点,Neutron 开发了对 GRE 模式的支持。GRE 是 L3 层的遂道技术,本质是在遂道的两端的 L4 层建立 UDP 连接传输重新包装的 L3 层包头,在目的地再取出包装后的包头进行解析。因为直接在遂道两端建立 UDP 连接,所以不需要在遂道两端路径的物理交换机上配置 TRUNK 的操作。

说说 GRE 的缺点吧:

  • GRE 将 L2 层的操作上移到 L3 层来做,性能肯定是会下降的。同时,由于遂道只能是点对点的,所以可以想象,如果有 N 个节点,就会有 N*(N-1)条 GRE 遂道,对于宝贵的 L4 层的端口资源也是一个浪费哦。那也是为什么 GRE 遂道使用 UDP 而不使用 TCP 的原因了,因为 UDP 用完后就可以释放,不用老占着端口又不用。
  • 在 Neutron 的 GRE 实现中,即使两台物理机上的两台虚机也不是直接建立 GRE 遂道的。而是通过 L3-agent 网络节点进行中转,这样做是基于方便使用 iptables 隔离网络流量的考虑。

利用 L3 层扩展 L2 层的遂道技术 VXLAN 与 SDN 的本质

VXLAN 是 VMware 的技术,可以克服 VLAN 号不足的问题;同时也可以克服 GRE 实质上作为点对点遂道扩展性太差的问题。

如果说 GRE 的本质是将 L3 层的数据包头重新定义后再通过 L4 层的 UDP 进行传输,那么 VXLAN 的本质就是对 L2 层的数据帧头重新定义再通过 L4 层的 UDP 进行传输。也就是笔者说的所谓的利用 L3 层扩展 L2 层.

既然 L2 层的数据帧头要重新定义,那就随便定义啦,是否满足以下三点是笔者从技术角度将一件产是否视为 SDN 的关键因素:

  • 可将 L7 层租户 tenant 的概念做到 L2 层。在笔者的前一篇《漫步云中网络》姊妹篇中已经介绍了 IaaS 云的本质就是卖虚机,即将虚机租给多租户使用后收费。所以位于 L7 应用层的 tenant 的概念是云用来对计算、存储、网络资源进行隔离的重要概念。那么将 tenant 的概念从 L7 层下移到 L2 层中意义重大。
  • 也可将类似 VLAN 的概念做到 L2 层,并且由于是软件定义的(不像物理交换机那样受硬件限制),那么很容易突破 VLAN 号在 1-4094 之间的限制。
  • 是否提供集中式的控制器对外提供北向 API 供第三方调用来动态改变网络拓扑。

清楚了 SDN 的本质,那么 VXLAN 的本质又是什么呢?

  • VXLAN 是一种 L2 层帧头的重新封装的数据格式。
  • VXLAN 仍然使用 GRE 遂道通过 UDP 传输重新封装帧头后的数据帧。

VXLAN 重新定义的 L2 层帧头格式如下图 1 所示,其中 VNI VXLAN ID 与 VLAN 的从概念上等同,但是因为它是用软件实现的,范围可用 24 bits 来表示,这就比 VLAN 的 1-4094 大多了。

图 1. VXLAN 帧头格式

VXLAN 帧头格式因为 VXLAN 通过重新定义 L2 层帧头(相当于通过 MAC 地址进行 NAT 的方案)从而让两个跨 L3 层的甚至广域网内的两个子网从 L2 层上互通。所以 VXLAN 的优点很多,能让遗留子网不改变 IP 地址的情况下无缝的迁移到云上来;也可以让虚机跨数据中心进行迁移(以前顶多只能在同一个 VLAN 里迁移)。

当然,VXLAN 也不是没有缺点的,通过上面的学习,大家已经知道 VXLAN 也是通过 GRE 走 UDP 来传输重定义的标准化的 VXLAN 封装格式的帧头的。由于在遂道的两端之间直接建立遂道,那么它是无法与途经的一些物理设备(如 DHCP 服务器)通信的,那么就需要 VXLAN 网关这种物理设备在遂道的中途截获 VXLAN 数据包(网关网关嘛,就是进行数据截获再转换的),解析里面的数据,然后做一些事情(像流量统计,DHCP 信息等等),最后再将数据重新打成 VXLAN 数据包交给遂道继续传输。可以想象,在所有需要与物理设备打交道的地方都是需要 VXLAN 网关的。觉得麻烦了吗?

利用 L2 层扩展 L3 层的标签技术 MPLS

VLAN 是一种标签技术,VLAN 一般用在局域网的交换机上,标签很容易在 L2 层通过硬件来实现转发。

MPLS 也是一种标签技术,原理类似于 VLAN,但一般用在 WAN 上的路由器上,下面我们说道说道。

对于 L3 层的传统路由转发来说一般是在路由表里查找相应的路由来实现。因为路由嘛,不同的 CIDR 之间可长可短,如 10.0.0.0/8 与 10.0.100.0/24 这两个子网首先长度不一样,其次 CIDR 号一个是 8,一个是 24,在路由器中,是通过字符串的按最长匹配算法来匹配路由的,那么应该选择 10.0.100.0/24 这个路由。字符串的按最长匹配算法很难通过硬件来实现,通过软件速度慢啊。那么广域网的路由器能不能也引入标签通过硬件转发的优点,在路由器作转发时,不再在 L3 层的通过软件去查找路由来实现转发,而是直接在 L2 层就通过标签通过硬件转发了呢?答案就是 MPLS。

例如 A 路由器通过 B 路由器给 C 路由器发包时,传统的路由器是根据目的地址进行转发,A 在开始转发时,并不知道去 C 的完整路由,它只知道转给 B,B 再决定转给 C,这种走一步看一步的叫基于目的地址的路由转发。但是 MPLS 的原理完全不同,A 在给 C 发包时,先发个 HELLO 包从 A 到 C 走一遍,在走的过程中就已经知道了 A 到 C 的路由路径并且根据 LDP(标签分发协议)将 A 到 C 的标签序列就事先确定好了。那样 A 再给 C 发数据时,A 就提前知道了在 L2 层怎么根据标签来转发,所以它不用再到 L3 层查找路由信息了,另外它在 L2 层通过标签转发可以很容易通过硬件来实现,这样速度更快了,最后标签的确定是通过 LDP 协议动态分配的这也避免了像 VLAN 的那种标签需要手工去设置的麻烦。

SDN

在 VXLAN 一节中,笔者已经说过了笔者判断一个产品是否是 SDN 产品的核心判断因素,即是否将 tenant 租户的概念做到了 L2 层并且提供了北向 API 供第三方应用调用动态调整网络拓扑。做到了,就是 SDN 产品。目前,SDN 产品主要有三类:

  • 基于 Overlay 技术的,如 VMware 的 VxLAN,如 Microsoft 的 NVGRE,如 IBM 的 Dove
  • 基于 OpenFlow 技术的
  • 基于专有技术的,如 Cisco 的 onePK

基于 Overlay 技术的 VxLAN 已经在上面介绍过了,这里着重介绍一下 OpenFlow 和 Dove。

OpenFlow

OpenFlow 是完全不同于传统网络技术的新兴网络技术。

传统交换机能通过自主学习建立转发表,然后根据转发表转发。但对于 OpenFlow 交换机,它是很“笨”的,数据帧来了它并不知道往哪个端口转发,不知道怎么办呢?不懂就问呗,找 OpenFlow 控制器问。控制器通过一定算法告诉它往哪个端口转发,然后 OpenFlow 交换机照着做就行了。下图 2 显示了 OpenFlow 的结构:

图 2. OpenFlow 的结构

OpenFlow 的结构我并没有将 OpenFlow 归于 L2 层,因为从理论上讲,它并不严格属于 L2 层,因为它设计了 L2-L4 层的转发项进行转发。现在 OpenFlow 的 FIB(转发信息表,Forward Info Base)中至少有下列条目:

  • L2 层的 MAC、VLAN 等
  • L3 层的 source ip, dest ip
  • L4 层的 source port, dest port
  • 甚至有基于 WAN 的动态路由的转发项,如 BGP、MPLS 等

OpenFlow 进行转发的时候和传统的网络技术不一样,传统的是存储包转发(数据到了 L2 层就解析出 MAC 地址进行转发,到了 L3 层后就解析出 IP 地址进行转发)。而 OpenFlow 则根据所谓的流进行转发。它将上面的 MAC、VLAN, source ip, dest ip, source port, dest port 等视作平等的平面,直接通过某个高效的字符串匹配算法匹配到了后再做某些动作,如 accept 或者 drop 掉。

再聊聊笔者所理解的 OpenFlow 的缺点。理论上,如果 OpenFlow 通过 L3 层的 IP 进行转发的话,那它就成了一个路由器了。但实际上,目前,OpenFlow 主要还是用在 L2 层当做一个交换机来使用的。如果真要在 L3 层和路由结合的话,那么它将以怎么样的方式和现存的分布式的动态路由协议(如 RIP、OSPF、BGP、MPLS)协作呢? 并且传统的 WAN 本来为了可靠就是以分布式来设计的,现在搞成 OpenFlow 式的集中式控制,监控什么的是方便了,但一旦控制器挂了那么整个网络也全挂了,并且 OpenFlow 控制器一旦被某方势力所掌握,那么整个 OpenFlow 网络也就全被掌握了,毕竟 WAN 是要考虑这些因素的。所以笔者不认为 OpenFlow 这种集中式控制的路由器能在 WAN 上将取代传统分布式的路由协议,顶多在 LAN 的 L2 层会有一些作为吧。

Dove/OpenDaylight

上面已经说到 SDN 需要对外提供北向 API 供第三方调用。

对于控制器与交换机之间的南向 API 的通讯标准就是由 google, facebook 这些用户主导定制的 OpenFlow 协议。

北向 API 没有标准,南向 API 也五花八门,将 tenant 和 VLAN 的概念做到 SDN 里也没有标准(虽然有 VMware 主导了一个 VXLAN 的数据封装格式),所以业界存在很多 SDN 的产品,Dove 便是由 IBM 实现的其中一种,OpenDaylight 的插件结构可以同时和众多的 SDN 控制器打交道,降低第三方应用同时和众多 SDN 控制器打交道的复杂性。

L3

L3 层的路由分静态路由和动态路由两种:

  • 在 Linux 中,通过打开 ipv4 forward 特性可以让数据包从一块网卡路由到另外一块网卡上。
  • 动态路由,如内部网关协议 RIP,OSPF;如外部网关协议 BGP。能够自动地学习建立路由表。

目前 Neutron 只支持静态路由,要点如下:

  • 对于不同 tenant 子网通过 namespace 功能进行隔离,在 Linux 中,一个命名空间 namespace 您可以简单理解成 linux 又启动了一个新的 TCP/IP 栈的进程。多个 tenant 意味着多个 namespace,也意味着多个 TCP/IP 栈。
  • 对于同一 tenant 中的不同子网的隔离通过 iptables 来做,也意味着,同一 tenant 中的相同子网的两个虚机不用走 L3 层,直接走 L2 层能通,没问题;但如果同一 tenant 中的不同子网的两个虚机要通讯的话,必须得绕道 L3-agent 网络节点,这是影响性能的。

L4-L7

LBaaS

OpenStack 最初的目标是做 x86 平台下的开源 IaaS 云,但它目前也有了类似于 LBaaS (Load Balance as a Service)这样本属于 SaaS 的特性。

LbaaS 服务可以为一个 tenant 下的多台虚机提供负载均衡服务,要点如下:

  • 提供负载均衡的虚机之间组成一个服务组
  • 虚机之间提供心跳检查
  • 外部通过 VIP 来访问 LB 服务组提供的服务,动态地将 VIP 根据负载均衡策略绑定到具体提供服务虚机的 fixed ip 上

下图 3 显示了 LBaaS 应用的几种情形:

图 3. LBaaS 的应用场景

LBaaS 的应用场景说明如下:

  • 有两个虚机 192.168.0.3 和 192.168.0.1 组成负载均衡池,它们之间做心跳
  • 如果这个 LB 服务只用在内网,可以只为虚机提供一个内部的 vip,如 192.168.0.4
  • 如果这个 LB 服务也需要从外部访问,那么这个 vip 可以做成 floating ip,如 10.1.1.10

所以实现上述 LB 服务的 neutron 命令如下:

清单 1. 实现例子 LB 服务的 neutron 命令
neurton lb-pool-create --lb-method ROUND_ROBIN --name mypool --protocol HTTP --subnet-id <subnet-id>

neurton lb-member-create --address 192.168.0.3 --protocol-port 80 mypool
neurton lb-member-create --address 192.168.0.1 --protocol-port 80 mypool
neurton lb-healthmonitor-create --delay 3 --type HTTP --max-retries 3 --timeout 3
neurton lb-healthmonitor-associate <lb-healthomonitor-id> mypool

neurton lb-vip-create --name myvip --protocol-port 80 --protocol HTTP --subnet-id  <subnet-id> mypool
neurton lb-vip-create --name myvip --protocol-port 80 --protocol HTTP --subnet-id  <subnet-id> mypool

neurton floatingip-create public
neurton floatingip-associate <floating-ip-id>  <lb-vip-port-id>

FwaaS

目前,Neutron 已经实现了一个 Security Group 服务,FWaaS 服务正在开发中。 FwaaS 和 Security Group 的原理差不多,只不过代码重构将以前 Security Group 的代码挪到了现有的 L4/L7 层框架来了;这样,以前 Security Group 作为 nova-compute 的一个组件只能运行在计算节点上,单纯拆出来做为一个独立进程之后也可以部署在 l3-agent 的那个物理机上提供边缘防火墙特性。下图 4 显示了 Security Group 服务的原理图:

图 4. Security Group 原理图

Security Group 原理图Security Group 由一系列的 iptables rule 组成

  • 这些 iptables rule 运行在计算节点上
  • 可以控制从虚机出去的流量
  • 可以控制进来虚机的流量
  • 可以控制虚机之间的流量

实施 Security Group 的步骤如下,例如,四个虚机,可以从 80 端口访问 web 虚机,从 web 虚机上可以访问 database 虚机,ssh 跳转虚机上可以同时访问 database 和 web 虚机,可以通过端口 22 访问 ssh 虚机。

清单2. 实施Security Group 的步骤
neutron security-group-create web
neutron security-group-create database
neutron security-group-create ssh
neutron security-group-rule-create --direction ingress --protocol TCP \
--port-range-min 80 --port-range-max 80 web
neutron security-group-rule-create --direction ingress --protocol TCP \
--port-range-min 3306 --port-range-max 3306 --remote-group-id web database
neutron security-group-rule-create --direction ingress --protocol TCP \
--port-range-min 22 --port-range-max 22 --remote-group-id ssh database
neutron security-group-rule-create --direction ingress --protocol TCP \
--port-range-min 22 --port-range-max 22 --remote-group-id ssh web
neutron security-group-rule-create --direction ingress --protocol tcp \
--port-range-min 22 --port-range-max 22 ssh

VPNaaS

我们仍然从技术的本质角度出发来解释什么是 VPN。VPN 类似于 GRE,也是一种遂道。但是不同的是 VPN 也要求不同的用户可以使用相同的子网,所以在每个建立 VPN 的两个端点所对应的边缘路由器上都会为每个用户建立它自己的 VPN 路由实例 VRF,白话一点的话,VRF 就是 Linux 里上面提到过的 namespace 的概念。

建立 GRE 遂道容易,但是 VPN 强调私密性,一个组织的 VPN 总不希望不经授权的访问吧。所以一般使用 SSL 或者 IPSec 结合 GRE 来建立 VPN。也可以通过 MPLS 来建立 VPN。Neutron 中这三类 VPN 目前均在开发之中。从下面 MPLS VPN 的 blueprint 中的图 5 可以看到将来要实现的样子:

图 5. MPLS VPN 实现原理图

MPLS VPN 实现原理图目前,l3-agent 没有使用动态路由,使用的是 namespace + ipv4 forward + iptables 的静态路由技术。l3-agent 现在充当着 CE 的角色(Custum Edge)。我们设想一下,笔者认为 BGPMpls Driver 将来至少要实现下列几个方面的内容:

  • 调用 PE API 在边缘路由器 PE 上通过 namespace 特性定义并配置 tenant 之间隔离的自己的 VPN 路由实例 VRF
  • tenant 定义的 VRF 路由并不需要在每个 WAN 核心路由上都存在,所以可以通过配置输入和输出策略实现,即使用 router-target import/export 命令导入或导出相应的 VRF 条目
  • 配置 PE 到 CE 的链路
  • 将 CE 的接口关联到预先定义的 VRF

Neutron 有什么?

Neutron 就是一个定义良好的插件框架,用来调用上述 L2-L7 层不同实现,且对外提供北向 API 来提供虚拟网络服务。

它自己提供了 tenant 的概念,它只是一个 SDN 框架,和底层的 SDN 软件如 Dove 集成时可以提供 SDN 的功能,但需要将它的 tenant 和 SDN 自身的 tenant 概念之间做一个映射。

L2

在 L2 层,由虚拟交换机来实现。虚拟交换机有下列这些种:

  • Linux 网桥,基于 Linux 内核的网桥。需要说明的是,网桥就是交换机,是交换机的一种常用的书面叫法。
  • OpenvSwitch(OVS):OVS 有两种模式,一种是当普通的虚拟交换机来使用,另一个是和 OpenFlow 控制器协作当作 OpenFlow 控制器来使用。
  • 一些基于 Overlay 技术的 SDN 实现,如 Dove 等。
  • 一些非开源的商业交换机。

目前,Neutron 已经实现的 L2 层插件如下图 6 所示,linuxbridge 实现了 Linux 网桥,openvswitch 插件实现了 openvswitch 网桥,bigswitch 插件实现了一种 SDN 控制器,ml2 是一种通用的插件(这些 L2 层的插件主要分写数据库的 plugin 部分和运行在计算节点的 agent 部分,plugin 写数据库的字段有差异但不多,所以代码重复,ml2 可以理解为一个公共的 plugin)。且每种插件基本上实现了 FLAT, VLAN, VXLAN, GRE 等四种拓扑。

图 6. Neutron 中 L2 层插件

Neutron 中 L2 层插件

L3

Neutron 的 L3 层由基于 namespace ipv4 forward + iptables 实现。

需要启动 l3-agent 进程,如果需要 DHCP 服务的话也需要启动 dhcp-agent 进程。

L4-L7

LBaaS 基于 Haproxy 实现;FWaaS 基于 iptables 实现;VPNaaS 有基于 IPSec 的 VPN 实现,也有基于 MPLS 的 VPN 实现,也有基于 SSL 的 VPN 实现。

截止到笔者写此文为止,目前只有 LBaaS 能用,其他的 FWaaS, VPNaaS 和 NATaaS 仍在开发中。但对于 FWaaS 有 Security Group 功能可用,区别在于前者由于作为独立服务也能部署在网络节点上提供边缘防火墙特性,后者依然能够在计算节点上使用 iptables 规则控制从虚机出去的,进来虚机的,虚机之间的流量。

结论

本文在《漫步云中网络》姊妹篇讲述 L2-L3 网络原理的基础上,继续讲述了最新的 Neutron 代码背后 L2-L7 层所依赖的网络技术内幕,让读者能够在心中建立起一个 High Level 的完整的 Neutron 架构图。

 

来源:https://www.ibm.com/developerworks/cn/cloud/library/1209_zhanghua_openstacknetwork/

 

 

发表评论