KVM虚机连不上外网,管理面怎么也ping不通,这种问题在OpenStack环境里实在不新鲜。但是同样现象背后的原因,可能差着十万八千里——有时候是安全组iptables规则冲突,有时候是命名空间里的路由表乱了,有时候是隧道MTU把大包全丢了,还有时候纯粹是OVS流表里的陈旧条目在作怪。我自己处理过不少形形色色的“Neutron网络故障”,很多问题在界面上看起来一模一样,实际排查路径却完全不同。这篇文章就把我做KVM虚拟化下Neutron网络诊断与修复的整套思路、常用命令、踩坑记录整理出来,希望能帮你少走点弯路。
这套方法特别适合正在维护OpenStack环境、又对虚拟网络底层比较陌生的朋友。不管你是用纯OVS还是有OVN介入,不管是VXLAN隧道还是VLAN模式,排查框架基本都是通用的。下面我从最常见的问题开始讲,然后一层层剥开Neutron网络的数据链路,最后给出具体的修复命令和避坑清单。
1. 故障初现:先从虚拟机内部说起
接到“虚机连不上网”这类工单,我从来不急着上计算节点查OVS,而是先登录虚机内部看一眼。很多人习惯性从宿主机开始抓包,这个顺序其实反了。虚拟机里的信息往往能直接告诉你故障方向,从外面查反而容易把简单问题复杂化。
1.1 虚拟机内部的三个快速检查
登录虚机后,我一般会依次做三件事:看网卡状态、看IP和路由、看ARP表。不要小看这三个基础命令,多数网络问题在第一轮就能定位个大概。
ip a ip route ip neigh这几个输出要重点确认几件事:
- 网卡有没有起来,MTU是多少,有没有收到RX/TX的error或drop。
- IP地址是否还在应有的网段里。DHCP租约过期导致IP丢失或者被重置,是很常见的“假故障”。
- 默认路由是否存在,下一跳是不是网关IP。
- ARP表里有没有对应的网关条目。如果网关条目缺失,说明二层就有问题。
如果发现ip route里面默认路由丢了,那多半和DHCP或者Neutron的subnet配置有关。如果ARP表里网关条目一直处于INCOMPLETE状态,那就是二层通信断了,要往虚机外的虚拟交换机方向查。
1.2 二层三层故障怎么区分
拿到虚机内部的信息后,下一步就是判断故障出在哪一层。我的做法是:先让虚机ping网关,再ping同网段另一个虚机,再ping外部地址(比如8.8.8.8或者机房里某台物理机)。
- 同网段通、网关通、外部不通:问题大概率在路由或NAT层,重点查router命名空间。
- 同网段不通:问题在二层,查安全组、OVS端口、隧道封装。
- 网关都不通:要么是虚机本身配置有问题,要么是网关所在的命名空间挂了,要么是承载网关的节点网络路径断了。
这里有个容易误判的场景:有些环境中虚机ping同网段另一个虚机是通的,但ping网关却不通。很多人第一反应是网关挂了,实际上很可能是安全组iptables规则把网关方向的流量拦了。Neutron的安全组默认是作用于虚机port的,但它会对虚机进出的流量都做过滤,如果规则里没放行到网关的流量,就会出现这种“半通”状态。
2. Neutron网络的核心组件与数据路径
要做诊断,脑子里必须有清晰的数据路径图。Neutron网络不像传统物理网络那么直观——它是由IP命名空间、Linux bridge、Open vSwitch、iptables规则和隧道协议共同组成的虚拟网络。任何一环出问题,表现都是“网络不通”,但修法完全不同。
2.1 命名空间:网络节点的“虚拟路由器”
Neutron的每个虚拟路由器、每个DHCP服务,都跑在独立的网络命名空间里。用ip netns list可以看到当前节点上所有的命名空间:
ip netns list qrouter-3b8d8f0e-5e6a-4c6f-9d3b-0a2f1c1e6b51 qdhcp-7f9b3a2e-8d2c-4f3e-9a8b-2c1d0e4f5a6bqrouter-开头的就是虚拟路由器,qdhcp-开头的就是DHCP服务。进入命名空间执行命令的方法是:
ip netns exec qrouter-3b8d8f0e-5e6a-4c6f-9d3b-0a2f1c1e6b51 ip a ip netns exec qrouter-3b8d8f0e-5e6a-4c6f-9d3b-0a2f1c1e6b51 ip route ip netns exec qrouter-3b8d8f0e-5e6a-4c6f-9d3b-0a2f1c1e6b51 ping 192.168.1.1排查外部网络不通时,第一步就是进router命名空间,看路由表是否完整、SNAT规则是否存在、端口IP是否正常。很常见的一个问题是router命名空间内与外部网络关联的那张网卡IP丢失,导致虚机无法对外通信。
2.2 安全组和iptables的“隐形链路”
安全组在Neutron中是通过宿主机上的iptables规则实现的。每创建一个虚机port,Neutron会在宿主机上注入一系列iptables链。虚机流量经过这些链时,会按规则放行或丢弃。
问题在于,规则链是动态生成的,一旦有规则配置冲突,或者iptables的某些表被其他操作覆盖,就会出现网络时通时断的现象。最常见的两个坑:
- 同一条链上既有
ACCEPT又有DROP,匹配顺序不对导致放行失效。 CONNMARK或ctstate相关的规则与已有的ESTABLISHED连接状态冲突,导致新连接被误判为无效。
排查安全组相关的诡异问题时,不要只看OpenStack界面上的安全组规则,一定要去宿主机上核对实际iptables规则:
iptables -L -n -v | grep 3b8d8f0e iptables -t nat -L -n -v如果安全组规则在界面上看起来没问题,但实际iptables链缺失,那很可能是同一个宿主机上同时跑着多个安全组件,或者有东西把链删了。这种情况重启neutron-openvswitch-agent服务通常能恢复。
2.3 MTU与VXLAN隧道:最隐蔽的性能杀手
VXLAN隧道把原始数据帧包上一层UDP头和新IP头,额外占用50字节左右。如果物理网络MTU是1500,隧道里传输的帧实际载荷就只有1450可用。虚机网卡的MTU如果保持1500,大包超过1450就会被丢弃,而小包能通。表现就是:ping小字节能通,ping大字节超时。
排查这类问题有个简单方法:在虚机里尝试设置不同MTU来对照:
ip link set eth0 mtu 1400 ping -M do -s 1472 192.168.1.1如果调低MTU后大包能通了,就是隧道MTU的问题。解决办法是把虚机网卡MTU、Neutron网络中配置的MTU、以及物理交换机端口的MTU统一调整,并确保物理链路支持足够大的帧,或者开启合理的jumbo frame。实际生产环境里,因为MTU不一致导致网络间歇性故障的案例非常多,而且很隐蔽,因为小包看起来一切正常。
3. 典型故障定位技巧
有了整体数据链路的概念,下面分享几个我实际遇到过的典型故障场景。每个场景我都会给出具体的排查命令和判断依据,你可以照着这个思路用自己的环境验证。
3.1 安全组规则冲突:虚机出得去进不来
某天某公司反馈:新建的虚机能访问外网,但从外部ping不通这个虚机的浮动IP。安全组规则已经把ICMP和SSH都放行了,Agent检查也是正常状态。
第一步我是去网络节点查浮动IP对应的router命名空间,确定SNAT和DNAT规则还在:
ip netns exec qrouter-3b8d8f0e-5e6a-4c6f-9d3b-0a2f1c1e6b51 iptables -t nat -L -n -v输出里面的DNAT规则正常,说明NAT层面没问题。接着去计算节点查安全组规则:
iptables -L -n -v | grep -i 3b8d8f0e结果发现neutron-openvswi-FORWARD链里多了一条DROP all规则,匹配顺序还在ACCEPT规则之前。这条规则是之前某次运维操作手动加上的,对全部端口生效,结果把入站流量全拦了。把误加的规则删掉后,虚机立即就能被ping通了。
这个案例想提醒一点:异常复杂的安全组问题,先别急着怀疑Neutron本身,检查宿主机上有没有人为干预过的iptables规则,往往比想象中更容易发现问题。
3.2 DHCP命名空间异常:虚机拿不到IP
第二种典型故障是虚机启动后拿不到IP,或者拿到IP后过一会儿又断。这通常是DHCP服务出了问题。
排查步骤是:
ip netns exec qdhcp-7f9b3a2e-8d2c-4f3e-9a8b-2c1d0e4f5a6b ps aux | grep dnsmasq ip netns exec qdhcp-7f9b3a2e-8d2c-4f3e-9a8b-2c1d0e4f5a6b ip a ip netns exec qdhcp-7f9b3a2e-8d2c-4f3e-9a8b-2c1d0e4f5a6b ip route确认dnsmasq进程存在、命名空间内的端口up、网关路由正确后,再检查dnsmasq的日志和lease文件。有次我发现dnsmasq一直在正常运行,但虚机就是拿不到IP。最后用tcpdump -i qdhcp-xxx抓包,发现虚机的DHCP DISCOVER广播包到了DHCP命名空间,但dnsmasq没有响应。原因是DHCP命名空间里的IP和虚机所在子网的前缀不匹配,这个端口IP是之前网络迁移操作时残留的错误地址。手动修正端口IP后,虚机秒拿IP。
如果虚机拿到IP后过一会儿又断,多半是网络中有两个DHCP服务在响应,或者IP冲突。可以用tcpdump -i any port 67 or port 68看是否有多条DHCP OFFER响应。
3.3 OVS流表与隧道端点故障
纯OVS模式下,虚机流量经过宿主机上的Open vSwitch转发,跨节点通信还要走VXLAN隧道。某次客户反馈:同宿主机上的虚机互通没问题,跨宿主机两台虚机ping不通。这就是典型的隧道或流表问题。
先看OVS的整体状态:
ovs-vsctl show重点检查隧道端口vxlan-*是否up,remote_ip是否正确,state是UP还是DOWN。如果隧道down了,看看是不是对端节点挂了,或者隧道端口被误删了。
再看流表项:
ovs-ofctl dump-flows br-int如果流表里对应某个MAC或者in_port的流缺失,二层转发就会失败。流量跨节点时,还需要确认br-tun(隧道网桥)上的流表是否正确:
ovs-ofctl dump-flows br-tun | grep -i vxlan有一次,跨节点ping不通,最后发现是br-tun上某个table的drop流被错误地排到了正常转发规则前面,导致VXLAN流量全被丢。清理流表后恢复正常,这种问题通过ovs-ofctl del-flows可以临时救急,但根本原因是某个配置下发过程出了错,需要看neutron-server的日志确认。
4. 实战修复过程:一次完整的外部网络故障
这里我分享一次完整的真实处理过程,涉及的是虚机无法访问外网的问题。整个过程经历了三层排查,最终定位到的是路由命名空间中的SNAT规则丢失,期间还伴随了一个ARP不响应的插曲。
4.1 确认虚机到网关的畅通
先登录虚机,确认内网基础连通性:
ip a ip route show ping 172.16.20.1虚机能ping通内网网关172.16.20.1,说明到network节点的二层和三层路径都是完好的。再ping一个公网地址,不通。这就可以判断问题出在虚拟路由器之后的NAT或者外网链路上。
4.2 查看router命名空间内的NAT规则
接着登录网络节点,用ip netns找到对应router命名空间:
ip netns list | grep qrouter ip netns exec qrouter-3b8d8f0e-5e6a-4c6f-9d3b-0a2f1c1e6b51 iptables -t nat -S POSTROUTING输出里居然没有SNAT规则。正常情况下,这里应该有一条约等于:
-A neutron-postrouting-bottom -o qg-xxxx -j SNAT --to-source 203.0.113.10没有SNAT规则就说明,凡是来自内网、发往外部网络的流量,源地址根本不会被转换成公网IP,自然无法在外网路由回来。为什么规则会消失?查了Neutron的日志,发现前一天晚上有一个agent restart,可能是在restart过程中iptables规则恢复没有完全生效。解决方案是强制同步一次网络配置:
openstack network agent list openstack network agent set --enable <agent-id> openstack network agent set --disable <agent-id> openstack network agent set --enable <agent-id>这里不推荐直接重启 neutron-server,比较安全的方式是先把对应计算节点上的neutron-openvswitch-agent或neutron-l3-agent做一次disable再enable,让规则自动重建。实际操作后,SNAT规则重新出现,虚机恢复了外网访问。
4.3 ARP不响应的问题和后续加固
修好SNAT后,虚机能访问外部了,但随之发现一个新问题:虚机ping外部偶尔不通,且时延抖动剧烈。用tcpdump在router命名空间里抓包:
ip netns exec qrouter-3b8d8f0e-5e6a-4c6f-9d3b-0a2f1c1e6b51 tcpdump -i qg-xxxx -n arp发现ARP请求频繁但没有响应。仔细看发现,网络节点上的qg-接口本身没有绑定浮动IP对应的MAC响应,因为该接口处于DOWN状态。原来之前一次cinder备份的误操作把这个接口down掉了。恢复:
ip netns exec qrouter-3b8d8f0e-5e6a-4c6f-9d3b-0a2f1c1e6b51 ip link set qg-xxxx up接口up后,ARP恢复正常,时延也稳了。这件事给我一个习惯:在任何Neutron网络修复后,我都会习惯性地抓一次ARP报文,确认路由命名空间的接口状态,而不是只看IP通不通。
4.4 修复后的验证步骤
完成修复后,建议做一套完整的验证,避免“修好了路由又断了安全组”这种反复:
# 虚机内部验证 ping -c 5 172.16.20.1 ping -c 5 8.8.8.8 curl -I http://example.com # 网络节点验证 ip netns exec qrouter-3b8d8f0e-5e6a-4c6f-9d3b-0a2f1c1e6b51 ip addr show ip netns exec qrouter-3b8d8f0e-5e6a-4c6f-9d3b-0a2f1c1e6b51 ip route show ip netns exec qrouter-3b8d8f0e-5e6a-4c6f-9d3b-0a2f1c1e6b51 iptables -t nat -L -n -v # 宿主机验证 ovs-vsctl show ovs-ofctl dump-flows br-int全部命令的输出符合预期之后,再把虚机重启一次,确认启动后自动获取的网络配置仍然正常。这一步很重要,因为有些修复只是临时的,虚机重启后还要复发。
5. 常见问题与经验速查
下面把我处理过的Neutron网络故障整理成速查表,按优先级排序。这个表是我每次遇到类似问题时的第一手参考资料。
5.1 快速诊断速查表
| 现象 | 优先排查点 | 关键命令 |
|---|---|---|
| 虚机完全无法上网 | 虚机网络配置、DHCP、安全组 | ip a、ip route、ip netns exec qdhcp-xxx |
| 出得去进不来 | 安全组、浮动IP映射、DNAT | iptables -t nat -L -n -v、openstack floating ip list |
| 大包不通小包通 | MTU、VXLAN隧道 | ping -M do -s 1472、ip link show |
| 跨节点不通 | OVS隧道、流表 | ovs-vsctl show、ovs-ofctl dump-flows br-tun |
| 同节点不同子网不通 | router命名空间、路由表 | ip netns exec qrouter-xxx ip route |
| 时通时断 | ARP老化、安全组conntrack | ip netns exec qrouter-xxx tcpdump -n arp |
| 重启后才正常 | agent状态、iptables规则重建 | openstack network agent list |
5.2 日常运维避坑建议
结合多年经验,有几个习惯特别值得养成:
- 任何网络变动操作前,先拍快照或记录当前iptables、OVS流表、命名空间路由表的输出,方便出问题时对比。
- 不要在宿主机上手动修改
neutron前缀的iptables链。即使当时觉得只是“临时加一条”,也很容易在后续操作中忘记清理。 - 关注MTU一致性,尤其在不同网络节点混合部署的场景。物理交换机、宿主机、虚机三者的MTU要统一规划。
- 定期检查
neutron-openvswitch-agent的日志,很多故障在发生前已经有大量报错记录,只是没人看。 - 网络排障时,越界的动作一定要记录时间点。很多诡异问题是因为操作顺序错乱导致的,比如先杀dnsmasq再同步配置文件,结果同步的是旧配置。
关于Neutron日志,我一般按这个优先级搜错误:先看/var/log/neutron/openvswitch-agent.log,再看neutron-server.log,最后看/var/log/syslog。不要把时间浪费在同时翻多个日志上,按链路一层层筛选信息更高效。
5.3 一个想想就亏的教训
最后分享一次让我印象深刻的教训。某次处理故障时,我在网络节点上手动执行了service openvswitch-switch restart,本来以为只是重启OVS服务,结果这个操作把整个br-int网桥上的所有流表清空了。当时几十台虚机的网络全部中断,紧急恢复花了接近两个小时。
自那以后,我再也不直接重启OVS服务来“刷新”流表。如果需要重建流表,我会先尝试局部操作:
ovs-ofctl del-flows br-int # 然后重启 neutron-openvswitch-agent 让它重新下发流表 service neutron-openvswitch-agent restart或者干脆用API层面的操作触发重配置,而不是动底层服务。这个教训让我深刻理解了Neutron的网络状态是存储在下发机制中的,而不仅仅是在OVS数据库中。任何粗暴的底层重启,都应该当作最后手段而不是第一手段。
KVM虚拟化下的Neutron网络故障排查,本质上是一个“分层还原”的过程。你把每一层的状态看清了,故障就藏不住了。命名空间、OVS、iptables、隧道、ARP、MTU,这六个要素掌握清楚,大部分问题都能自主解决。上面的命令和思路都是我实际用过的,踩过坑,所以写出来希望对正在排除类似问题的朋友有点帮助。如果你也遇到过特别隐蔽的Neutron网络故障,不妨顺着这个思路重新排查一遍,说不定答案就在某一层的输出里。