VLAN 只有 12 位,共 4096 个,对于云平台的隔离问题,不够用。
所以,要扩展 VLAN 协议,在原来的包的格式的基础上扩展出一个头,里面包含用于区分租户的 ID,外层的包的和格式尽量和传统一样,很像隧道协议。
底层的物理网络设备组成的网络为 Underlay 网络,用于虚拟机和云中的技术组成的网络为 Overlay 网络。
两个 Overlay 技术:GRE 和 VXLAN,可解决云计算中的 VLAN 限制。
GRE
Generic Routing Encapsulation,IP-over-IP 的隧道技术,将 IP 包封装在 GRE 包里,外加 IP 头,在隧道的一端封装数据包,并在通路上传输,到另外一端解封装。
1、GRE 头
- GRE 头中,前 32 位固定,后面可选。
- 4 位标识位,标识后面是否有可选项。
- 32 位 key 字段,区分用户的 Tunnel ID,远大于 VLAN ID 数。
- 下方的格式是专门用于网络虚拟化的 GRE 包头格式,称为 NVGRE,网络 ID 24 位,远大于 VLAN ID 数。
路由器需要有封装和解封装 GRE 包的能力。
2、使用 GRE 隧道传输过程
IP 为 192.168.1.102 的主机 A 要访问 IP 为 192.168.2.102 的主机 B,因跨网段,先发给默认网关,即路由器 192.168.1.1。
路由表发现去网段 192.168.2.0/24 应该走 GRE 隧道,从隧道一端的网卡 Tunnel0 进入隧道。
Tunnel 隧道的端点进行包的封装,在内部 IP 头外加 GRE 头。对于 NVGRE,是在 MAC 头外加 GRE 头,然后加上路由器的外网 IP 地址。源 IP 172.17.10.10,目标 IP 172.16.11.10,然后从 E1 的物理网卡发送到公网。
在公网,全部按公网 IP 地址沿着路由器一跳跳走。
网络包到达对端的 Tunnel0,解封装,取下外层 IP 头,根据路由表,从 E3 口转发到服务器 B。
3、GRE 不足
- Tunnel 数量问题。GRE 是一种点对点隧道,如果网络数目增多,隧道数目会呈指数性增长。
- GRE 不支持组播。
- 目前还有很多防火墙和三层网络设备无法解析 GRE。
VXLAN
GRE 是在三层外再套三层,VXLAN 则从二层外就套了一个 VXLAN 头,包含的 VXLAN ID 为 24 位,同样远大于 VLAN ID 数。VXLAN 头外还封装了 UDP、IP,及外层 MAC 头。
对 VXLAN 的包封装和解封装的功能点为 VTEP(VXLAN Tunnel Endpoint)。VTEP 相当于虚拟网络管家。每台物理机上都有 VTEP,虚拟机启动时向其注册。
不同于 GRE,VXLAN 支持组播。当一个 VTEP 启动时,通过 IGMP 协议加入一个组播组。
通信过程:
- 虚拟机 1、2、3 属于云中同一个用户的虚拟机,因而分配相同的 VXLAN ID = 101。
- 虚拟机 1 发送 ARP 广播,请求虚拟机 2 的 MAC 地址。
- ARP 请求到底 VTEP1 时, VTEP1 知道虚拟机 2 不归自己管,将 ARP 请求封装在 VXLAN 中,组播出去。
- VTEP2、VTEP3 都收到消息,都会解开 VXLAN 包,里面有 ARP。
- VTEP3 在本地广播,无机器回复自己的 MAC;VTEP2 在本地广播,虚拟机 2 回复自己的 MAC。
- VTEP2 学到虚拟机 1 归 VTEP1 管,将 ARP 回复封装在 VXLAN 中,单播给 VTEP1。
- VTEP1 解开 VXLAN 包,发现 ARP 回复,发送给虚拟机 1。
- VTEP1 也学到虚拟机 2 归 VTEP2 管,下次直接发给 VTEP2 即可。
如何将 GRE 和 VXLAN 融入云平台?
创建一个网络拓扑结构:
三台物理机,每台上有两台虚拟机,分属两个不同的用户,不互相通信,因而 VLAN tag 不同。但不同物理机上的相同用户,可通过 GRE 隧道相互通信。
为什么多一个 br1 虚拟交换机?可将虚拟机之间的互联和物理机之间的互联分两层设计,这样就可使用不同种隧道,OpenvSwitch 支持三类隧道:GRE、VXLAN、IPsec_GRE。
Flow Table 规则都设置在 br1 上,每个 br1 都有 3 个网卡,网卡 1 对内,网卡 2、3 对外。
Flow Table 的设计:
- Table 0 是所有流量的入口,进入 br1 的流量中,分两种: 从port 1 进来的,是发出去的流量,由 Table 1 处理;从 port 2、3 进来的,是进入物理机的流量,由 Table 3 处理;都没匹配上,丢弃。
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=1 in_port=1 actions=resubmit(,1)"
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=1 in_port=2 actions=resubmit(,3)"
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=1 in_port=3 actions=resubmit(,3)"
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=0 actions=drop"
- Table 1 处理出去的网络包,分两种:单播,由 Table 20 处理;多播,由 Table 21 处理。
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=1 table=1 dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,20)"
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=1 table=1 dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,21)"
- Table 2 紧接着 Table 1,既不是单播,也不是多播,默认丢弃。
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=0 table=2 actions=drop"
- Table 3 处理所有进来的网络包,需将隧道 Tunnel ID 转换为 VLAN ID。如果匹配不上 Tunnel ID,默认丢弃;否则,转换为相应的 VLAN ID,跳到 Table 10。
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=0 table=3 actions=drop"
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=1 table=3 tun_id=0x1 actions=mod_vlan_vid:1,resubmit(,10)"
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=1 table=3 tun_id=0x2 actions=mod_vlan_vid:2,resubmit(,10)"
- 对于进来的包,Table 10 进行 MAC 学习,然后从 port 1 发出去。
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=1 table=10 actions=learn(table=20,priority=1,hard_timeout=300,NXM_OF_VLAN_TCI[0..11],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:0->NXM_OF_VLAN_TCI[],load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[],output:NXM_OF_IN_PORT[]),output:1"
- MAC 学习结果存放在 Table 20 中。如果 Table 20 为空,说明没有进行 MAC 学习,进行广播,交给 Table 21 处理。
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=0 table=20 actions=resubmit(,21)"
- Table 21 处理多播的包。如果匹配不上 VLAN ID,默认丢弃;否则,将 VLAN ID 转换为 Tunnel ID,从 port 2 和 port 3 都发出去,进行多播。
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=1table=21dl_vlan=1 actions=strip_vlan,set_tunnel:0x1,output:2,output:3"
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=1table=21dl_vlan=2 actions=strip_vlan,set_tunnel:0x2,output:2,output:3"