Openstack中的虚拟机流量通常被分为东西向和南北向。而测试环境中可能会遇到各种流量问题,搞清楚每种流量的通路有助于出现问题后的快速定位。
计划将分多篇博文,掰开来详细分析openstack中的各种流量路径。
本文以最简单的单节点为例,介绍在同子网下,虚拟机之间相互访问的流量路径
环境说明
- Openstack: stein(all in one)
- Host: Ubuntu 18.04
- Network driver: openvswitch
必要准备
- 外部网络:MyEx
- 镜像:cirros
- flavor: small
实验
同子网虚拟机
创建网络
1 | $ openstack network create net1 |
创建虚拟机
1 | $ openstack server create --flavor small --image cirros --network net1 --min 2 --max 2 vm |
分别创建了:
vm-1: 200.0.0.16
vm-2: 200.0.0.224
先确认两个虚机的连通性
发生了什么?
linux bridge
1 | $ brctl show |
先不关注
brq459c374c-d3
的网桥
Openstack
先来记录一下openstack上的port信息
1 | $ openstack port list |
id | 用途 | ip |
---|---|---|
a333499b-e5 | 外部网络MyEx的DHCP port | 192.168.0.2 |
a95f52ba-a2 | vm-2 | 200.0.0.224 |
e013286e-b7 | 租户网络net1的DHCP port | 200.0.0.2 |
ebeae637-5c | vm-1 | 200.0.0.16 |
网络接口
1 | $ ip link show |
上面出现了两个id
:a95f52ba-a2
和ebeae637-5c
,分别对应了openstack的两个port的id
而对于同一个id
,有4个前缀:qbr
,qvb
,qvo
,tap
:
前缀 | 说明 |
---|---|
qbr | Linux网桥 |
qvb | 与qvo互为veth pair,qvb置于qbr网桥中 |
qvo | 与qvo互为veth pair,qvo置于br-int的ovs网桥中 |
tap | tap接口,与虚拟机中的网卡组成veth pair |
namespace
1 | $ ip netns list |
2个namespace的id
分别对应了openstack上的两个network的id
1 | $ openstack network list |
namespace中:
1 | $ ip netns exec qdhcp-459c374c-d347-4c3d-8dca-7dbb6b403f4f ifconfig |
-
每个namespace各有一个接口:
tape013286e-b7
和tapa333499b-e5
-
这两个接口因为在namespace中,在
ip link show
的时候看不到。 -
其
id
也分别对应了openstack中的port的id
,后面会看到这两个接口出现在ovs的br-int
中
openvswitch
1 | $ ovs-vsctl show |
br-int
下有4个port:tapa333499b-e5
,tape013286e-b7
,qvoebeae637-5c
,qvoa95f52ba-a2
,这4个接口在前面都有提及
port | 说明 |
---|---|
tapa333499b-e5 | MyEx的dhcp相关,位于qdhcp-04d375a6-76... 的namespace中 |
tape013286e-b7 | net1的dhcp相关,位于qdhcp-459c374c-d3... 的namespace中 |
qvoebeae637-5c | 通过veth peer接口qvbebeae637-5c 与vm-1连接 |
qvoa95f52ba-a2 | 通过veth peer接口qvoa95f52ba-a2 与vm-2连接 |
ovs流表
为了方便观察,手动删除了
cookie
和duration
字段
1 | $ ovs-ofctl dump-flows br-int |
先忽略icmp6的流表
table=0
- in_port为
qvoebeae637-5c
和qvoa95f52ba-a2
的arp报文送往table=24 - in_port为
qvoebeae637-5c
和qvoa95f52ba-a2
的其他报文送往table=25 - 其他报文送往table=60
table=24
- in_port为
qvoebeae637-5c
和qvoa95f52ba-a2
的arp报文,arp_spa分别是200.0.0.224
和200.0.0.16
的报文,送往table=25
table=25
- in_port为
qvoebeae637-5c
和qvoa95f52ba-a2
的报文,目的mac分别为fa:16:3e:17:60:c2
和fa:16:3e:53:d5:50
的报文,送往table=60
table=60
- 正常转发
通过上面一系列的流表,in_port为
qvoebeae637-5c
和qvoa95f52ba-a2
的报文基本上都会在br-int
上正常转发
梳理一下
- vm通过vnet与一个tap接口相连
- tap接口与qvbxxx接口置于一个linux网桥中
- qvbxxx的veth peer置于br-int的ovs网桥中
- dhcp服务位于linux namespace中,使用了一个tap接口,而此tap接口同时位于br-int的ovs网桥中
报文跟踪
vm之间互通
分析
根据上面的图我们可以看到,vm-1访问vm-2的流量路径为:
- tapebeae637-5c
- qbrebeae637-5c
- qvbebeae637-5c
- qvoebeae637-5c
- br-int
- qvoa95f52ba-a2
- qvba95f52ba-a2
- qbra95f52ba-a2
- tapa95f52ba-a2
抓包
实际上这个抓包很无聊,因为每个上面看到的报文都是一样的,这里只列举其中一个的结果
1 | $ tcpdump -i qvoebeae637-5c |
vm-1访问dhcp的port
分析
而访问dhcp的通路,前面到达br-int的报文都一样,到了br-int后,会到达对应的namespace中
1. 在vm-1上ping 200.0.0.2
2. 在ovs中抓包
1 | $ ovs-tcpdump -i tape013286e-b7 |
3. 在namespace中抓包
注意,在namespace中抓包,报文信息可能不会及时打印在屏幕上
1 | $ ip netns exec qdhcp-459c374c-d347-4c3d-8dca-7dbb6b403f4f tcpdump -i tape013286e-b7 |
More
你或许已经发现了,在namespace中的接口的IP为169.254.169.254
,这个地址是干嘛的?那么200.0.0.2
到底在哪儿呢?
169.254.169.254
在openstack中,你会经常看到这个IP地址,它是metadata service的IP
大多数cloud os实例启动时,都会向这个IP地址发起请求,获取一些信息,如以下实例启动日志中,获取public-keys
和user-data
1 | Starting network... |
200.0.0.2在哪儿?
1 | $ ps -aux | grep dnsmasq |
--dhcp-leasefile
指向了/var/lib/neutron/dhcp/459c374c-d347-4c3d-8dca-7dbb6b403f4f/leases
,这个文件记录了dhcp分配的IP地址:
1 | $ cat /var/lib/neutron/dhcp/459c374c-d347-4c3d-8dca-7dbb6b403f4f/leases |
200.0.0.2
的mac地址是fa:16:3e:45:00:dc
,而这个mac正是tape013286e-b7
的物理地址
1 | $ ip netns exec qdhcp-459c374c-d347-4c3d-8dca-7dbb6b403f4f ifconfig |
小结
在单节点状况下,同子网下的虚拟机相互访问,是一个非常简单的路径。
通过tap接口、veth pair、linux网桥、ovs网桥以及ovs流表来实现了流量通路。