本帖最后由 eying 于 2016-1-6 16:21 编辑
问题导读:
1.如何设置Neutorn 网络节点的 eth1?
2.Neutron MTU 方案有哪些?
3.怎样配置VxLAN + Linux bridge 网络环境中的 MTU ?
3. 实验和分析
3.1 Neutorn 网络节点的 eth1 使用默认 MTU 1500,其它设备使用 MTU 1450
(1)网络节点上:在 qdhcp network name 中执行 ping 命令:指定数据大小为 1422,加上 ICMP header 8 字节和 IP header 20 字节,共 1450 字节。
[mw_shl_code=applescript,true]root@controller:~# ip netns exec qdhcp-18fc2ba1-057c-4c88-b523-8470fc31ecc1 ping -M do -i 1 -c 2 -s 1422 70.0.0.150
PING 70.0.0.150 (70.0.0.150) 1422(1450) bytes of data.
1430 bytes from 70.0.0.150: icmp_seq=1 ttl=64 time=1.89 ms
1430 bytes from 70.0.0.150: icmp_seq=2 ttl=64 time=1.47 ms[/mw_shl_code]
(2)网络节点上:tap 设备收到的 ethernet frame 长度为 1464 (IP 包总长 1450 字节 + ethernet header 14 字节)
[mw_shl_code=applescript,true]17:21:22.327944 fa:16:3e:32:35:ef > fa:16:3e:85:06:8e, ethertype IPv4 (0x0800), length 1464: (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 1450)
70.0.0.100 > 70.0.0.150: ICMP echo request, id 18979, seq 1, length 1430[/mw_shl_code]
(3)网络节点上:vxlan interface 收到的frame 和 tap 设备收到的是一样的,长度 1464
[mw_shl_code=applescript,true]17:23:44.027648 fa:16:3e:32:35:ef > fa:16:3e:85:06:8e, ethertype IPv4 (0x0800), length 1464: (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 1450)
70.0.0.100 > 70.0.0.150: ICMP echo request, id 19059, seq 1, length 1430[/mw_shl_code]
(4)网络节点上:用于虚机数据网络的网卡 eth1 收到的帧长 1514 (1464 + vxlan header 8 + udp header 8 + IP header 20 + ethernet header 14 = 1514 )
[mw_shl_code=applescript,true]17:27:27.577163 52:54:00:7c:c0:79 > fa:80:13:21:6b:56, ethertype IPv4 (0x0800), length 1514: (tos 0x0, ttl 64, id 9573, offset 0, flags [none], proto UDP (17), length 1500) # vxlan 封包帧
10.0.0.10.56309 > 10.0.0.13.8472: [no cksum] OTV, flags [I] (0x08), overlay 0, instance 1074
fa:16:3e:32:35:ef > fa:16:3e:85:06:8e, ethertype IPv4 (0x0800), length 1464: (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 1450) #原始二层帧
70.0.0.100 > 70.0.0.150: ICMP echo request, id 19163, seq 2, length 1430[/mw_shl_code]
注意:eth1 的 MTU 是 1500,但是 1500 是指 IP 包的最大长度,而不将 ethernet header 计算在内,因此,此帧可以被顺利发到物理网络。
(5)计算节点上:物理网卡 eth1 收到的帧长是 1514
[mw_shl_code=applescript,true]17:46:42.039327 52:54:00:7c:c0:79 > 01:00:5e:00:00:01, ethertype IPv4 (0x0800), length 1514: (tos 0x0, ttl 1, id 61037, offset 0, flags [none], proto UDP (17), length 1500)
10.0.0.10.56309 > 224.0.0.1.8472: [no cksum] OTV, flags [I] (0x08), overlay 0, instance 1074
fa:16:3e:32:35:ef > fa:16:3e:85:06:8e, ethertype IPv4 (0x0800), length 1464: (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 1450)
70.0.0.100 > 70.0.0.150: ICMP echo request, id 19375, seq 1, length 1430[/mw_shl_code]
(6)计算节点上:vxlan interface 收到的帧长为 1464。可见,它收到的包已经经过 linux vxlan 内核模块解包了。
[mw_shl_code=applescript,true]17:48:27.051651 fa:16:3e:32:35:ef > fa:16:3e:85:06:8e, ethertype IPv4 (0x0800), length 1464: (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 1450)
70.0.0.100 > 70.0.0.150: ICMP echo request, id 19412, seq 1, length 1430[/mw_shl_code]
(7)计算节点上:包顺利到底 tap 和 虚机的 eth0,直至 ICMP 协议处理函数。
3.2 Neutorn 网络节点的 eth1 使用默认 MTU 1500,其它设备使用默认 MTU,其中 ns 的 MTU 为 1500。有诡异的问题。
(1)同样在 qdhcp namespace 中执行 ping 操作。考虑到其 MTU 为 1500,因此,最大的数据块长度可以为 1500 - 28 = 1472。但是没有收到回应包,失败。
[mw_shl_code=applescript,true]root@controller:~# ip netns exec qdhcp-18fc2ba1-057c-4c88-b523-8470fc31ecc1 ping -M do -i 1 -c 2 -s 1472 70.0.0.150
PING 70.0.0.150 (70.0.0.150) 1472(1500) bytes of data.[/mw_shl_code]
而在对应的 tap 设备上,tcpdump 没有输出。因此可以看出,因为 tap 设备的 MTU 是 1450,导致长度为 1500 的包没法通过。
(2)同样在 qdhcp namespace 中执行 ping 操作,但是不设置数据长度,其 IP 包长度为 84。成功。这是因为 IP 包长度 84 是在 MTU 范围之内。
[mw_shl_code=applescript,true]root@controller:~# ip netns exec qdhcp-18fc2ba1-057c-4c88-b523-8470fc31ecc1 ping -M want -i 1 -c 2 70.0.0.150
PING 70.0.0.150 (70.0.0.150) 56(84) bytes of data.
64 bytes from 70.0.0.150: icmp_seq=1 ttl=64 time=1.99 ms
64 bytes from 70.0.0.150: icmp_seq=2 ttl=64 time=1.37 ms[/mw_shl_code]
在 tap 设备上的帧长度为 98 = 84 + ethernet header 14 字节
[mw_shl_code=applescript,true]17:47:42.335841 fa:16:3e:32:35:ef > fa:16:3e:85:06:8e, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 26932, offset 0, flags [DF], proto ICMP (1), length 84)
70.0.0.100 > 70.0.0.150: ICMP echo request, id 19734, seq 1, length 64[/mw_shl_code]
(3)从 qrouter 中使用 ssh 连接虚机(第一次连接一个新虚机),ssh 停留在 “debug1: SSH2_MSG_KEXINIT sent”,失败
[mw_shl_code=applescript,true]root@controller:~/s1# ip netns exec qrouter-b94a203d-5317-4d0b-9833-5c65e01bd76f ssh -i ubuntu.pem ibmcloud@70.0.0.152 -vvv
OpenSSH_6.6.1, OpenSSL 1.0.1f 6 Jan 2014
debug1: Reading configuration data /etc/ssh/ssh_config
...
debug3: load_hostkeys: loading entries for host "70.0.0.152" from file "/root/.ssh/known_hosts"
debug3: load_hostkeys: loaded 0 keys
debug1: SSH2_MSG_KEXINIT sent[/mw_shl_code]
在 ns 端口对应的 tap 设备上做 tcpdump,看起来象是客户端的 ssh 有关数据在发往虚机的过程中被截断了:
[mw_shl_code=applescript,true]18:40:35.405723 fa:16:3e:32:35:ef > fa:16:3e:3f:3b:2a, ethertype IPv4 (0x0800), length 96: (tos 0x0, ttl 64, id 29605, offset 0, flags [DF], proto UDP (17), length 82)
70.0.0.100.53 > 70.0.0.152.58164: [bad udp cksum 0x8d4b -> 0x0ff4!] 397 Refused q: A? changelogs.ubuntu.com.openstacklocal. 0/0/0 (54)
18:40:35.406534 fa:16:3e:3f:3b:2a > fa:16:3e:32:35:ef, ethertype IPv4 (0x0800), length 96: (tos 0x0, ttl 64, id 43407, offset 0, flags [DF], proto UDP (17), length 82)
70.0.0.152.58164 > 70.0.0.100.53: [udp sum ok] 41422+ AAAA? changelogs.ubuntu.com.openstacklocal. (54)[/mw_shl_code]
(4)将 qrouter 的 qr inteface 的 MTU 改为 1450,则 ssh 成功。查看成功连接过程中的数据包,只发现下面的包比较可疑,因为它达到了物理网络的 MTU:
[mw_shl_code=applescript,true]18:51:58.539087 52:54:00:7c:c0:79 > fa:80:13:21:6b:56, ethertype IPv4 (0x0800), length 1514: (tos 0x0, ttl 64, id 31536, offset 0, flags [none], proto UDP (17), length 1500)
fa:16:3e:19:15:fe > fa:16:3e:3f:3b:2a, ethertype IPv4 (0x0800), length 1464: (tos 0x0, ttl 64, id 19222, offset 0, flags [DF], proto TCP (6), length 1450)
70.0.0.1.56611 > 70.0.0.152.22: Flags [.], cksum 0xd128 (correct), seq 44:1442, ack 42, win 221, options [nop,nop,TS val 25021385 ecr 218717], length 1398[/mw_shl_code]
当 MTU 是 1500 的话,该帧的大小将会是 1564,它超过了其它网络接口的 MTU,因此,它应该无法到达虚机。但是,这只是猜测,具体原因未知,但是修改 MTU 为 1450 确实可以解决问题。
4. Neutron MTU 方案
- 默认地,物理网卡的 MTU 为 1500 字节。
- Linux vxlan 在创建 vxlan interface 时,设置其 MTU 为所绑定物理网卡 MTU 减去 50,即 1450.
- Linux bridge 上的其它 tap 设备,包括虚机的网卡、network namespace (包括 l3 和 dhcp)的 interface 相应的 tap 设备的 MTU 都是 1450.
- 默认情况下,虚机的网卡、network namespace (包括 l3 和 dhcp)的 interface 的 MTU 都是 1500。
- 因此,虚机和 network namespace 中的软件产生的数据包在通过这些 network interface 转发到 vxlan interface 时如果其数据帧超过 (1450 + 14 = 1464)字节时将会被丢弃,这将导致一些奇怪的问题,比如上面谈到的 ssh 无法连接等。
下面分别介绍两个workaround。
4.1 增加物理网卡和相关 linux bridge interface 的 MTU
在虚机网络接口使用默认 MTU 1500 时,
(1)需要设置物理网卡和相关 linux bridge interface 的 MTU 为 1550。 (3)另外,如果你的物理网络已经使用巨帧(jumbo frame),那么虚机网络接口的 MTU 的问题自动被规避了。
4.2(Kilo版本中)降低虚拟网络接口(virtual network interface)的 MTU
虚拟网络接口包括两种,分别有不同的配置方法:
4.2.1 虚机网卡的 MTU 设置:使用 MTU selection and advertisement 机制
包括以下步骤:
(1)在 network 中增加 mtu 属性,目前该属性对于 Neutron API 只可见,不可以修改,默认值为 0 。 ticket。
[mw_shl_code=applescript,true]'mtu': {'allow_post': False, 'allow_put': False, 'is_visible': True}[/mw_shl_code]
(2)通过有关配置参数设置 network 的 mtu。目前在 /etc/neutron/plugins/ml2/ml2_conf.ini 中有如下几个相关参数。
[mw_shl_code=applescript,true]# =========== items for MTU selection and advertisement =============
31 # (IntOpt) Path MTU. The maximum permissible size of an unfragmented
32 # packet travelling from and to addresses where encapsulated Neutron
33 # traffic is sent. Drivers calculate maximum viable MTU for
34 # validating tenant requests based on this value (typically,
35 # path_mtu - max encap header size). If <=0, the path MTU is
36 # indeterminate and no calculation takes place.
37 # path_mtu = 0
38
39 # (IntOpt) Segment MTU. The maximum permissible size of an
40 # unfragmented packet travelling a L2 network segment. If <=0,
41 # the segment MTU is indeterminate and no calculation takes place.
42 # segment_mtu = 0
43
44 # (ListOpt) Physical network MTUs. List of mappings of physical
45 # network to MTU value. The format of the mapping is
46 # <physnet>:<mtu val>. This mapping allows specifying a
47 # physical network MTU value that differs from the default
48 # segment_mtu value.
49 # physical_network_mtus =
50 # Example: physical_network_mtus = physnet1:1550, physnet2:1500
51 # ======== end of items for MTU selection and advertisement ========= [/mw_shl_code]
physical_network_mtus : 对 provider network 使用,适用于 flat 和 vlan 类型的虚拟网络。
[mw_shl_code=applescript,true]def get_mtu(self, physical_network):
seg_mtu = super(FlatTypeDriver, self).get_mtu()
mtu = []
if seg_mtu > 0:
mtu.append(seg_mtu)
if physical_network in self.physnet_mtus:
mtu.append(int(self.physnet_mtus[physical_network]))
return min(mtu) if mtu else 0[/mw_shl_code]
path_mtu:设置租户网络的最大可能 MTU。
segment_mtu :租户网络的默认 MTU
三个配置参数结合不同的租户网络类型来确定其 MTU:
- Flat/VLAN:Minimum of (segment_mtu or physical_network_mtus)
- GRE: Minimum of (segment_mtu, path_mtu) 减去 42
- VXLAN: Minimum of (segment_mtu, path_mtu) 减去 50
配置这些 MTU 参数后,neutron net-show 命令就可以显示每个网络的 mtu 了。
注意:这些 MTU 设置不能仅对某一个租户网络使用,而是适合于同类型的所有网络。
(3)在 neutron.conf 中增加配置项 advertise_mtu,默认值为 false。在设置为 true 后,DHCP 将想申请/renew的固定地址的网卡广告 network 的 mtu。
[mw_shl_code=applescript,true]# =========== items for MTU selection and advertisement =============
# Advertise MTU. If True, effort is made to advertise MTU
# settings to VMs via network methods (ie. DHCP and RA MTU options)
# when the network's preferred MTU is known.
# advertise_mtu = False
# ======== end of items for MTU selection and advertisement =========
if cfg.CONF.advertise_mtu:
mtu = self.network.mtu #network.mtu 由第(2)步确定
# Do not advertise unknown mtu
if mtu > 0:
cmd.append('--dhcp-option-force=option:mtu,%d' % mtu)[/mw_shl_code]
4.2.2 设置 neutron 网络节点上 network namespace 的 qr/ns/qg 以及它们对应的 tap 设备等虚拟网络接口的 MTU
在 neutron.conf 中设置配置项 network_device_mtu 的值来指定这些网络节点的 MTU:
[mw_shl_code=applescript,true]if self.conf.network_device_mtu:
root_veth.link.set_mtu(self.conf.network_device_mtu)
ns_veth.link.set_mtu(self.conf.network_device_mtu)[/mw_shl_code]
4.2.3 总结 VxLAN + Linux bridge 网络环境中的 MTU 配置
配置文件 | 配置项 | 默认值 | 需要修改为 | 生效的虚拟网络接口 | 生效步骤 | neutorn 控制节点上的 neutron.conf | network_device_mtu | none(此时 mtu 为 1500,这会带来诡异的问题,见上面 3.2 部分的描述) | 1450 | neutron 网络节点上的 qdhcp 和 qrouter network namespace 的 qr,qg 和 ns 接口以及对应的 veth tap 设备; 还需要在 dhcp_agent.ini 和 l3_agent.ini 文件中设置 interface_driver = neutron.agent.linux. interface.BridgeInterfaceDriver | 对存在的 qdhcp 和 qrouter netns: 1. 修改 neutron.conf 文件 2. 确定 qrouter 的 interface 3. stop dhcp 和 l3 agent 4. 删除已有的 qdhcp 和 qrouter network name 5. 删除 qrouter 所有interface 对应的 veth 设备,其名称为 'tap' +interafce name 去掉前缀 6. 启动 dhcp 和 l3 agent 7. 检查 qdhcp 和 qrouter netns 中的 interface 的 mtu 对修改后新建的netns,自动生效。 | neutorn 控制节点上的 ml2_conf.ini | segment_mtu | 0 (使用默认 mtu) | 1500 | 对 GRE 和 VxLAN 类型的租户 网络适用, 取 (segment_mtu 和 path_mtu) 之间的小者减去 42 或者 50 | | path_mtu | 0 (使用默认 mtu) | 1500 | 见下文示例2 | physical_network_mtus | 空 (使用默认 mtu) | 1500 | 对 flat 和 vlan 类型的 provider
network 适用,取(segment_mtu 和 physical_network_mtus)
之间的较小值 | 见下文示例1 | neutorn 控制节点上的 neutron.conf | advertise_mtu | false (默认不广告 mtu 给客户机网卡) | true | 使得 DHCP 能对虚机的
网卡广告所在网络 MTU 值 | |
示例1:创建 mtu 为 1600 的 flat 类型的provider network:
(1)修改neutorn 控制节点上的 ml2_conf.ini配置文件:physical_network_mtus = physnet1:1600 flat_networks = external, physnet1 (2)重启neutron-server 服务 (3)创建 flat 类型网络:neutron net-create --provider:network_type flat --provider:physical_network physnet1 flatextnet2
[mw_shl_code=applescript,true]root@controller:~# neutron net-create --provider:network_type flat --provider:physical_network physnet1 flatextnet2
Created a new network:
+---------------------------+--------------------------------------+
| Field | Value |
+---------------------------+--------------------------------------+
| admin_state_up | True |
| id | 9270a2bf-7e63-4001-884c-4c48e1b0f5e5 |
| mtu | 1600 |
| name | flatextnet2 |[/mw_shl_code]
示例2:创建 mtu 为 1450 的 VxLAN 租户网络并启动虚机
(1)修改neutorn 控制节点上的 ml2_conf.ini配置文件:path_mtu = 9000 segment_mtu = 1500 (2)重启neutron-server 服务 (3)创建 vxlan 类型的租户网络:
[mw_shl_code=applescript,true]root@controller:~# neutron net-create test111
Created a new network:
+---------------------------+--------------------------------------+
| Field | Value |
+---------------------------+--------------------------------------+
| admin_state_up | True |
| id | 901a5ba3-be92-440f-b7ca-ff277b527ea5 |
| mtu | 1450 |
| name | test111 |
| provider:network_type | vxlan |[/mw_shl_code]
(4)在该网络中创建启用 dhcp 的 subnet
(5)检查 dnsmasq,会发现它已经使用了 dhcp-option-force 参数,其中 mtu 的值就是该网络的 mtu 值
[mw_shl_code=applescript,true]nobody 18930 1 0 10:45 ? 00:00:00 dnsmasq --no-hosts --no-resolv --strict-order --bind-interfaces --interface=ns-9022f50c-a8 --except-interface=lo --pid-file=/var/lib/neutron/dhcp/901a5ba3-be92-440f-b7ca-ff277b527ea5/pid --dhcp-hostsfile=/var/lib/neutron/dhcp/901a5ba3-be92-440f-b7ca-ff277b527ea5/host --addn-hosts=/var/lib/neutron/dhcp/901a5ba3-be92-440f-b7ca-ff277b527ea5/addn_hosts --dhcp-optsfile=/var/lib/neutron/dhcp/901a5ba3-be92-440f-b7ca-ff277b527ea5/opts --dhcp-leasefile=/var/lib/neutron/dhcp/901a5ba3-be92-440f-b7ca-ff277b527ea5/leases --dhcp-range=set:tag0,20.0.0.0,static,86400s --dhcp-option-force=option:mtu,1450 --dhcp-lease-max=256 --conf-file=/etc/neutron/dnsmasq.conf --domain=openstacklocal[/mw_shl_code]
(6)在该子网中创建虚机,其网卡的 mtu 值将是 1450.
(7)注意:目前(Kilo)版本中,网络的 mtu 值计算只在它被创建的时候,也就是说,对于已经存在的网络,无法再修改它的 mtu 值了。
4.3 (Kilo版本之前)设置客户机网卡的 MTU
Kilo 版本之前需要手工修改 dnsmasq 的配置来达到差不多同样的效果,通过下面的步骤:
- 编辑 /etc/neutron/dhcp_agent.ini 文件,在 [DEFAULT] 部分添加 dnsmasq_config_file = /etc/neutron/dnsmasq-neutron.conf
- 创建和编辑 /etc/neutron/dnsmasq-neutron.conf 文件,添加 dhcp-option-force=26,1450
- 杀掉当前 dnsmasq,重启 dhcp agent
和 4.2.1 的区别在于,Kilo 版本中可以计算不同虚机网络的 MTU,而 Kilo 版本之前使用的dnsmasq 配置文件中的配置项只能所有的网络使用同样的 mtu。
|