问题
VPC内虚机通过NAT网关配置SNAT访问外网。如下所示:

使用中出现问题,虚机不能访问外网。
基础知识
DVR模式
按照 Neutron 原先的设计,所有网络服务都在网络节点上进行,这意味着大量 的流量和处理,给网络节点带来了很大的压力。这些处理的核心是路由器服务。 任何需要跨子网的访问都需要路由器进行路由。很自然,能否让计算节点上也运 行路由器服务?这个设计思路无疑是更为合理的,但具体实施起来需要诸多细节 上的技术考量。
为了降低网络节点的负载,同时提高可扩展性,OpenStack 自 Juno 版本开始正 式引入了分布式路由(Distributed Virtual Router,DVR)特性,来让计算节 点自己来处理原先的大量东西向流量和非 SNAT 南北流量。这样网络节点只需要 处理少部分的 SNAT流量,大大降低了负载和整个系统对网络节点的依赖。
DHCP 服务、VPN 服务目前仍然需要集中在网络节点上进行。
虚机的各种口
虚机流量发出,经过以下路径:

- TAP 设备是一种工作在二层协议的点对点网络设备,每一个 TAP 设备都有一 个对应的 Linux 字符设备,用户程序可以通过对字符设备的读写操作,完成 与 Linux 内核网络协议栈的数据交换工作,在虚拟化环境中经常被模拟器使 用。总而言之,TAP设备其实就是一个Linux内核虚拟化出来的一个网络接口。
- qbr,是一个Linux Bridge。因为OpenStack是把iptables规则丢在TAP设备实 现了安全组功能。但OVS跟Iptables的规则不兼容,有iptable的tap设备不能直接连接到ovs上。 所以用了一个折衷的方式,在中间加一层,使用qbr linux桥。
- qvb 和qvo,虚拟ethernet接口,通常以pair的方式出现,一端发出的网包,会被另一端接收,可以形成两个网桥之间的通道。
- br-int:bridge-integration,综合网桥,常用于表示实现主要内部网络功能 的网桥。
- iptables:Linux 上常见的实现安全策略的防火墙软件。
- TUN设备:模拟一个三层的网络设备,可以接受和发送三层网包。
dvr模式下,虚机报文路径
虚机通过snat网关访问外网,报文发出去流向是:
tap->qbr->qvb->qvo->br-int->qrouter->br-int->br-tun1->br-tun2。
路径上的qvo、qvb口和tap口都可以抓包。
dvr模式下,报文头封装及改变
以下图说明了报文的改变,主要是二层头的封装。

如上图所示,租户两个子网,红色和绿色,分别有 vm1 和 vm2,位于节点 cn1 和 cn2 上。
vm1 访问 vm2 的网包如步骤 1-6,整个过程 ip 保持不变。
- 原始包,vm1 访问 vm2,目的 mac 为本地(红网)的路由器网关接口 r1 red mac;
- 经过 br-int-cn1 转发,该网包通过本地(红网)网关接口扔给本地路由器 r1。
- r1 根据路由规则,经过到绿网的接口发出,此时网包的源 mac 改为绿网的网关接口 r1 grn mac,目的 mac 改为 vm2 mac,并且带上绿网的本地 vlan tag;
- 网包发给 br-tun-cn1 进行 tunnel,扔出去之前,将源 mac 替换为跟节点相关的特定 mac dvr cn1 mac,之后带着目标子网(绿网)的 外部 tunnel id 扔出去(实现可以为 vlan、vxlan、gre 等,功能都是一样的);
- 节点 cn2 的网桥 br-tun-cn2 会从 tunnel 收到这个包,解封包,带上本地 vlan tag,最终抵达网桥 br-int-cn2;
- br-int-cn2 上替换网包的源 mac(此时为 dvr-cn1-mac)为本地路由器的绿网网关接口,然后发给 vm2。
分析排查
通过openstack命令,查到虚机的port,所在计算节点信息,所连接的qrouter信 息。
- 查看虚机的port信息
~# openstack port list –server ed079656-c1d5-415e-bb79-c24dbbc54cdf
- 查看虚机所在计算节点
~# openstack server show ed079656-c1d5-415e-bb79-c24dbbc54cdf | grep host
- 查看虚机所在的网络
~# openstack port show 74df9649-bd57-4a5e-8b7e-181c3e7a2a40 | grep network
- 查看接入qrouter的port
~# openstack port list –long –network c0ad68cc-2388-406c-9da0-e2ec4fe71b5e | grep dis
- 根据port查到qrouter的id
~# openstack port show 8d2bd1cf-bcf1-43e3-bf57-0c965a88e0e0 | grep device
device_id即是qrouter的id。
报文抓包
- 登陆计算节点
- 首先从报文的tap口抓包,确认流量是不是正常发出。
- qbr抓包,确认liunux桥的安全组是否已经放行。如果tap口能抓到包,但qbr 没有,说明安全组规则把包拦截了。
- qrouter抓包,确认是否正常
- br-tun查看报文是否正常发送出去
期间如果抓不到正常的报文,需要排查原因。
qbr抓不到包
qbr抓不到报文,但tap口正常。这种情况,应该是安全组规则把报文拦截了。需 要排查计算节点上的安全组规则。安全组的排查方式,参考安全组相关文档。
pbr规则排查
查看qrouter上的规则
~# ip netns exec qrouter-e6d4c905-4c62-4f06-a879-0bd6f4a8330d bash
~# ip rule
~# ip route show table 2886729985
正常发送出去,但对端没收到
从计算节点的物理口上抓包,查看是否正常收到报文。
总结
根据虚机发送报文时,沿着报文的路径进行抓包,对没有收到包的前一个节点重 点排查。