分享

Neutron VxLAN + Linux Bridge 环境中的网络 MTU【上】

问题导读:




1.什么是MTU?
2.怎样VxLAN封包和GRE封包?

3.Linux vxlan + bridge 环境中的网络栈是什么?








1. 基础知识

1.1 MTU

一个网络接口的 MTU 是它一次所能传输的最大数据块的大小。任何超过MTU的数据块都会在传输前分成小的传输单元。MTU 有两个测量层次:网络层和链路层。比如,网络层上标准的因特网 MTU 是 1500 bytes,而在连接层上是 1518 字节。没有特别说的时候,往往指的是网络层的MTU。

  要增加一个网络接口 MTU 的常见原因是增加高速因特网的吞吐量。标准因特网 MTU 使用 1500byte是为了和 10M 和 100M 网络后向兼容,但是,在目前1G和 10G网络中远远不够。新式的网络设备可以处理更大的MTU,但是,MTU需要显式设置。这种更大MTU的帧叫做“巨帧”,通常 9000 byte 是比较普遍的。

  相对地,一些可能得需要减少MTU的原因:

  • 满足另一个网络的MTU的需要(为了消除UDP分包,以及需要TCP PMTU discover )
  • 满足 ATM cell 的要求
  • 在搞出错率线路上提高吞吐量

MTU 不能和目前任何 Internet 网络协议混在一起,但是,可以使用一个路由器将不同 MTU 的网段连在一起。

  修改配置网络接口 MTU 的方式:

  • 自动的:通过 DHCP MTU 广告。注意,只有 DHCP 租期被续了以后,MTU 设置才会生效。你可以将网络接口 down 再 up 强制它马上生效。
  • 手动临时性的:ifconfig eth0 mtu 9000
  • 永久性的:修改 network interface 定义文件。以 Debian/Ubuntu 为例,

auto eth0iface eth0 inet static        address 192.168.0.2        netmask 255.255.255.0        mtu 9000

1.2 VxLAN 封包(Mac-in-UDP,以 ping 产生的 ICMP 包为例)和 MTU

1.jpg

步骤操作/封包协议长度MTU
1ping -s 1422ICMP1430 = 1422 + 8 (ICMP header)
2L3IP1450 = 1430 + 20 (IP header)VxLAN Interface 的 MTU
3L2Ethernet1464 = 1450 + 14 (Ethernet header)
4VxLANUDP1480 = 1464 + 8 (VxLAN header) + 8 (UDP header)
5L3IP1500 = 1480 + 20 (IP header)物理网卡的(IP)MTU,它不包括 Ethernet header 的长度
6L2Ethernet1514 = 1500 + 14 (Ethernet header) 最大可传输帧大小

因此,VxLAN 的 overhead 是1514- 1464 = 50 byte。

1.3 GRE 封包(IP-in-IP,以 ping 产生的 ICMP 包为例)和 MTU
2.jpg

步骤操作/封包协议长度备注
1ping -s 1448ICMP1456 = 1448 + 8 (ICMP header) ICMP MSS
2L3IP1476 = 1456 + 20 (IP header)GRE Tunnel MTU
3L2Ethernet1490 = 1476 + 14 (Ethernet header)经过 bridge 到达 GRE
4GREIP1500 = 1476 + 4 (GRE header)+ 20 (IP header) 物理网卡 (IP)MTU
5L2Ethernet1514 = 1500 + 14 (Ethernet header)最大可传输帧大小

因此,GRE 的 overhead 是 1514 - 1490 = 24 byte(为啥 Neutron 中的 GRE overhead 是 42?)。

可见,使用 GRE 可以比使用 VxLAN 每次可以多传输 1448 - 1422 = 26 byte 的数据。

1.4 IP Fragmentation (分包) 和 Path Maximum Transmission Unit Discovery (PMTUD)

1.4.1 IP 分包

先谈几个要点:

  • 分包是指将一个IP包分成多个传输,在接收端 IP 层重新组装
  • 一个 IP 包能否分包,取决于它的 DF 标志位:DF bit (0 = "may fragment," 1 = "don't fragment")
  • 分包后,每个分段有 MF 标志位:MF bit (0 = "last fragment," 1 = "more fragments")

分包示例:

3.jpg

第一个表格中:

  • IP 包长度 5140,包括 5120 bytes 的 payload
  • DF = 0, 允许分包
  • MF = 0, 这是未分包

第二个表格中:

  • 0-0 第一个分包: 长度 1500 = 1480 (payload) + 20 (IP Header). Offset(起始偏移量): 0
  • 0-1 第二个分包: 长度 1500 = 1480 (payload) + 20 (IP Header). Offset: 185 = 1480 / 8
  • 0-2 第三个分包: 长度 1500 = 1480 (payload) + 20 (IP Header). Offset: 370 = 185 + 1480/8
  • 0-3 第四个分包: 长度 700 =  680 (payload, = (5140 - 20) - 1480 * 3) + 20 (IP Header) . Offset: 555 = 370 + 1480/8

需要注意的是,只有第一个包带有原始包的完整 IPv4 + TCP/UDP 信息,后续的分包只有 IPv4 信息。

分包带来的问题:

  • sender overhead:需要消耗 CPU 去分包,包括计算和数据拷贝。
  • receiver overhead:重新组装多个分包。在路由器上组装非常低效率,因此组装往往在接收主机上进行。
  • 重发 overhead:一个分包丢失,则整个包需要重传。
  • 在多个分包出现顺序错开时,防火墙可能将分到当无效包处理而丢弃。

1.4.2 TCP MSS:TCP Maximum Segment Size (TCP 最大段长)

TCP MSS,是指一个接收方期望在一个 TCP/IP 报文里面接收的数据(payload)的长度。

4.jpg

  MSS 的值受两个值的约束:发送方和接收方的用于存储一个 TCP/IP 报文中的TCP数据的buffer 的长度的小者,以及该值和整个传输路径的最小 MTU 减去40 的小者。而最小MTU 由 PMTU 确定。

1.4.3 PMTU 路径MTU发现

  PMTU 的用途是动态的确定从发送端到接收端整个路径上的最小 MTU,从而避免分包。注意,PMTU 只支持 TCP,对其他协议比如 UDP 无效。而且,如果发送方已经开启了 PMTU,那么它发送的所有 TCP/IP 包的 DF 标志都被设置为 1 即不再允许分包。当网络路径上某个路由器发现发送者的包因为超过前面转发路径的 MTU 而无法发送时,它向发送者返回一个 ICMP  "Destination Unreachable" 消息,其中包含了那个 MTU,然后发送者就会在它的路由表中将该mtu值保存下来,再使用较小的 MTU 重新发出新的较小的包。

在 Linux 系统上,可以打开或者关闭 PMTU:

/proc/sys/net/ipv4/ip_no_pmtu_disc #0,打开,默认值;1,关闭 (sysctl -w net.ipv4.ip_no_pmtu_disc=1)Set this if you want to disable Path MTU discovery - a technique to determine the largest Maximum Transfer Unit possible on your path. See also the section on Path MTU discovery in the Cookbook chapter.

  一个路由器作为主机包的转发者的通常做法:

  • 检查 IP 包的 DF 标志位
  • 检查 IP 包的 大小是否超过带转发端口的 MTU
  • 如果超过,而且 DF = 0 ,则将它分成多个包再发送 (分包)
  • 如果超过,而且 DF = 1,则向发生着返回一个 ICMP 消息,并将包丢弃 (PMTU)
  • 如果不超过,则转发 (转发)

例子1:超过 MTU,DF = 0 => 路由器分包、发送,接收主机组装

5.jpg

例子2:超过,DF = 1 => PMTU,发送者重新以小包发送

6.jpg


2. Linux vxlan + bridge 环境中的网络栈和 MTU

2.1 QEMU/KVM 计算节点上的网络栈

2.1.1 协议栈
7.jpg

  • 红线:QEMU/KVM 主机网卡接收外部网络包并发给虚机
  • 黑线:虚机上的应用发出网络包经过 QEMU/KVM 主机网卡发出

补充说明一下使用 virtio_net 时客户机网卡 eth0 和 主机上的 tap 设备之间的关系:

   8.jpg 10.jpg

  • 虚机的网络流量是通过 virtio_net queue 发到 QEMU/KVM 主机上的 QEMU 的
  • QEMU 再交给主机上的 tap 设备

可见,eth0 和 tap 设备是不直接连接的,而是需要经过 QEMU。

2.1.2 各个 network interface 的 MTU

每个 network interface 都可以设置不同的 MTU,用来限制经过它的最大 IP payload 的长度。这些 network interface 包括:

  • 虚机 eth0
  • 主机 tap 设备
  • 主机 vxlan interface
  • 主机 网卡 eth1

网络接口MTU来源说明
物理网卡 eth0 1500    安装系统时指定,未指定则使用默认值 1500用于虚机的数据网络的物理网卡
vxlan interface1450由 linux vxlan 内核模块创建该interface对应的 ip 设备时指定,其 MTU 为绑定的网卡的MTU 值减去 50
tap 设备1450
由 linux bridge 在添加 tap 到 linux bridge 时指定为该 bridge 所有 port 的最小 MTU。
dev_set_mtu(br->dev, br_min_mtu(br))
和虚机 eth0 通过 QEMU virtio 连接
虚机 eth01450当 Neutron DHCP 的 advertise_mtu 配置项有设置值时,由该值决定;否则,使用默认的 1500neutron 代码

从上图也可以看出,

  • 主机网卡 eth1 的默认 MTU 是 1500 bytes,当然你可以修改
  • 网络包经过 vxlan interface 到达 eth1 的过程中,Linux vxlan 内核模块会将网络包二层帧封装成 UDP 包,因此,vxlan interface 必须设置适当的 MTU 来限制通过它的网络包的大小(从 1.2 章节可以看出,vxlan interface 的 MTU 需要比它所绑定的物理网卡的 MTU 小 50),否则,封装后的包会被 eth1 丢弃。
  • tap 设备和虚机 eth0 的 MTU 是相同的,因为 QEUM 只是转发,而没做封装之类的处理。而因为 vxlan interface MTU 需要缩小,因此它们的 MTU 也要相应缩小。因为 eth0 到 vxlan interface 之间没什么包封装,因此,它们的 MTU 可以一致。

2.2 Neutron 网络节点上的协议栈

9.jpg

网络接口MTU来源说明
物理网卡 eth0 1500                 安装系统时指定,未指定则使用默认值用于虚机的数据网络的物理网卡
vxlan interface1450
由 linux vxlan 内核模块创建该interface对应的 ip 设备时指定,其 MTU 为绑定的网卡的MTU 值减去 50
tap 和 qr/ns/qg 是 veth 的两端
tap 设备1450
由 linux bridge 在添加 tap 到 linux bridge 时指定为该 bridge 所有 port 的最小 MTU。因为 vxlan interface 的 MTU 是
1450, 因此tap 设备的 MTU 也是 1450.
dev_set_mtu(br->dev, br_min_mtu(br))
qr/ns/qg network interface 及对应的tap设备1500
由 Neutorn 根据其配置项 conf.network_device_mtu 来设置:设置了其值时,设置MTU为该值;否则,不指定时,则使用默认值1500。
可见这里有个问题,这个 MTU 和 tap 的 MTU 应该一致,但是 conf.network_device_mtu 没有默认值,因此不配置该值的时候,其 MTU 为 1500,这将导致和 tap 的 MTU 不一致。后面会分析该不一致导致的问题。
neutron 代码
物理网卡 eth11500neutorn 有配置项时使用配置的值,具体见下面的分析;没有时,使用默认值 1500.用于访问外网的物理网卡







没找到任何评论,期待你打破沉寂

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条