Linux bridge实现虚拟交换机的基本原理

openstack创建port流表 openstack创建网络_openstack

br0是linux bridge,br0充当虚拟交换机的作用,负责将物理网卡eth0和虚拟机网卡tap设备vnet0/vnet1连接到同一个二层网络,实现虚拟机VM1和VM2,以及虚拟机与外网之间的通信。

 

Linux-bridge支持local、flat、vlan和vxlan四种网络类型,目前不支持gre。

一、local  network

(1)、不会与宿主机的任何物理网卡相连,也不关联任何的vlan id。

(2)、ML2 linux-bridge会创建一个bridge,instance的tap设备会连接到bridge。位于同一个local network的instance会连接到相同的bridge上,instance之间可以通信。

(3)、bridge没有与物理网卡连接,因此instance无法与宿主机之外的网络通信。

openstack创建port流表 openstack创建网络_openstack_02

讨论底层网络发生了怎样的变化?network 的 subnet 和port 信息

openstack创建port流表 openstack创建网络_网络_03

上述端口绑定的是dhcp服务器。

 

当在计算节点创建一个新的虚拟机的时候,底层网络又会怎么变化呢?

对于 instance“cirros-vm1”,Neutron 会在 subnet 中创建一个 port,分配 IP 和 MAC 地址,并将 port 分配给 cirros-vm1。

openstack创建port流表 openstack创建网络_交换机_04

openstack创建port流表 openstack创建网络_交换机_05

当 cirros-vm1 启动时:

1. 宿主机上的 neutron-linuxbridge-agent 会根据 port 信息创建 tap 设备,并连接到 local 网络所在的 bridge

2. 同时该 tap 会映射成cirros-vm1 的虚拟网卡,即 virtual interface (VIF)。

 

openstack创建port流表 openstack创建网络_openstack_06


二、flat network

flat network是不带tag的网络,要求宿主机的物理网卡直接与linux bridge相连,意味着每个flat network都会独占一个物理网卡。

 

openstack创建port流表 openstack创建网络_openstack_07

三、DHCP服务

neutron提供DHCP服务的组件是DHCPagent。默认通过dnsmasq实现DHCP功能。

1、使用linux bridge连接DHCP namespace interface

   当创建network并在subnet上enableDHCP时,网络节点上的DHCP agent会启动一个dnsmasq进程为该network提供DHCP服务。

   dnsmasq是一个提供DHCP与DNS服务的开源软件。dnsmasq与network是一一对应的关系,一个dnsmasq进程可以为同一个network中所有使能DHCP的子网提供服务。

 

2、用linux network namespace隔离dnsmasq服务

(1)、二层网络上,VLAN可以将一个物理交换机分割成几个独立的虚拟交换机。  三层网络中,linux network namespace可以将物理三层网络划分为几个独立的虚拟三层网络。每个namespace都有自己的独立网络栈,包括route table、firewall rule、network interface device等。

(2)、neutron通过namaspace为每个network提供独立的DHCP和路由服务,允许租户创建重叠的网络。没有namespace,网络不能重叠,失去灵活性。

 

宿主机本身也有rootnamspace,拥有所有物理和虚拟interface device.

 

对于 flat_net 的 DHCP 设备 tap19a0ed3d-fe,需要将其放到 namespace qdhcp-f153b42f-c3a1-4b6c-8865-c09b5b2aa274 中,但这样会带来一个问题:

tap19a0ed3d-fe 将无法直接与 root namespace 中的 bridge 设备 brqf153b42f-c3 连接。

Neutron使用 vethpair 解决了这个问题

veth pair 是一种成对出现的特殊网络设备,它们象一根虚拟的网线,可用于连接两个 namespace。向 veth pair 一端输入数据,在另一端就能读到此数据。

 

tap19a0ed3d-fe 与 ns-19a0ed3d-fe 就是一对 veth pair,它们将qdhcp-f153b42f-c3a1-4b6c-8865-c09b5b2aa274 连接到brqf153b42f-c3。如下图所示:

openstack创建port流表 openstack创建网络_openstack创建port流表_08

ip netns exec<\network namespace name> <\command> 管理 namespace。

 

四、vlan network

vlan network 是带 tag 的网络,是实际应用最广泛的网络类型。

 

1、三个 instance 通过TAP 设备连接到名为 “brqXXXX” linux bridge。

2、在物理网卡 eth1 上创建了 eth1.100 的 vlan interface,eth1.100 连接到 brqXXXX。

3、instance 通过eth1.100 发送到 eth1 的数据包就会打上vlan100 的 tag。

如果再创建一个network vlan101,eth1 上会相应的创建vlan interface eth1.101,并且连接的新的 lingux bridge “brqYYYY”。

每个 vlannetwork 有自己的 bridge,从而也就实现了基于vlan 的隔离。

 

openstack创建port流表 openstack创建网络_IP_09

cirros-vm1 位于控制节点,属于 vlan100

cirros-vm2 位于计算节点,属于 vlan100

cirros-vm3 位于计算节点,属于 vlan101

 

cirros-vm1 与 cirros-vm2 都在vlan100,它们之间能通信

cirros-vm3 在 vlan101,不能与cirros-vm1 和 cirros-vm2 通信

那怎么样才能让 vlan100与 vlan101 中的 instance 通信呢?

单靠二层 vlan 是不行的,还得在三层通过路由器转发。(二层数据进行隔离,只能通过三层路由功能进行实现,不同网段间进行通信)

 

五、routing 路由功能

路由服务提供跨subnet互联互通的功能。借助物理路由器或者虚拟router。

1、物理router

openstack创建port流表 openstack创建网络_openstack_10

接入的物理 router 有两个 interface ip:

172.16.100.1 对应 vlan100 的网关。

172.16.101.1 对应 vlan101 的网关。

 

当 cirros-vm1 要跟 cirros-vm3 通信时,数据包的流向是这样的:

(1). 因为 cirros-vm1 的默认网关指向 172.16.100.1,cirros-vm1 发送到 cirros-vm3 的数据包首先通过 vlan100 的 interface 进入物理 router。

(2). router 发现目的地址 172.16.101.3 与 172.16.101.1 为同一个 valn,则从 vlan101 的 interface 发出。

(3). 数据包经过 brq1d7040b8-01 最终到达 cirros-vm3。

 

2、虚拟router

虚拟 router 的路由机制与物理 router 一样,只是由软件实现。

Neutron的路由服务是由L3 Agent提供的。L3 Agent通过iptables提供firewall和 floating ip服务。

 

l3 agent 会为每个 router 创建了一个 namespace,通过 veth pair 与 TAP 相连,然后将 Gateway IP 配置在位于 namespace 里面的 veth interface 上,这样就能提供路由了。通过 ip netns 查看 namespace:

通过 ip netnsexec < namespace name> ip a 命令查看 router_100_101namespace 中的 veth interface 配置。

openstack创建port流表 openstack创建网络_网络_11

namespace 中有两个 interface:

 

(1)、qr-e17162c5-00 上设置了 Gateway IP 172.16.101.1,与 root namespace 中的 tape17162c5-00 组成 veth pair。

(2)、qr-d568ba1a-74 上设置了 Gateway IP 172.16.100.1,与 root namespace 中的 tapd568ba1a-74 组成 veth pair。

openstack创建port流表 openstack创建网络_openstack_12

解决不同虚拟交换机之间进行数据通信。虚拟router实现不同的subnet间路由。

namespace 中的路由表也保证了 subnet_172_16_100_0 和 subnet_172_16_101_0 之间是可以路由的。

 

openstack创建port流表 openstack创建网络_openstack创建port流表_13

上一节我们讨论了Neutron 将虚拟 router 放置到namespace 中实现了不同 subnet 之间的路由。

今天探讨为什么要用namespace 封装 router?

为什么不直接在tape17162c5-00 和 tapd568ba1a-74 上配置 Gateway IP,而是引入一个 namespace,在 namespace 里面配置 Gateway IP 呢?

 

首先考虑另外一个问题:

如果不用 namespace,直接 Gareway IP 配置到 tape17162c5-00 和 tapd568ba1a-74 上,能不能连通 subnet_172_16_100_0 和 subnet_172_16_101_0 呢?

 

答案是可以的,只要控制节点上配置了类似下面的路由。

Destination GatewayGenmask Flags Metric Ref Use Iface

172.16.100.0 *255.255.255.0 U 0 0 0 tapd568ba1a-74

172.16.101.0 *255.255.255.0 U 0 0 0 tape17162c5-00

既然不需要namespace 也可以路由,为什么还要加一层 namespace 增加复杂性呢?

其根本原因是:为了支持网络重叠。

 

云环境下,租户可以按照自己的规划创建网络,不同租户的网络是可能重叠的。

将路由功能放到namespace 中,就能隔离不同租户的网络,从而支持网络重叠。

下面通过例子进一步解释。

Tenant A vlan100subnet A-1: 10.10.1.0/24 {“start”: “10.10.1.1”, “end”: “10.10.1.254”}

Tenant A vlan101subnet A-2: 10.10.2.0/24 {“start”: “10.10.2.1”, “end”: “10.10.2.254”}

 

Tenant B vlan102subnet B-1: 10.10.1.0/24 {“start”: “10.10.1.1”, “end”: “10.10.1.254”}

Tenant B vlan103subnet B-2: 10.10.2.0/24 {“start”: “10.10.2.1”, “end”: “10.10.2.254”}

A,B 两个租户定义了完全相同的两个 subnet,网络完全重叠

(1)、不使用namespace的场景

     其特征是网关IP配置在TAP interface上。  路由条目只能记录到控制节点操作系统的路由表中。

(2)、使用namespace的场景

     网关IP配置在namespace中的vethpair上。 每个namespace有自己的路由表。

这样的路由表是可以工作的。

 

例如 vlan102 上有数据包要发到 vlan103。

选择路由时,会查看router_102_103 的路由表, 匹配第二个条目,数据通过 qr-4 被正确地发送到 vlan103。

同样当 vlan100 上有数据包要发到 vlan101时,会匹配 router_100_101 路由表的第二个条目,数据通过 qr-2 被正确地发送到 vlan101。

可见,namespace 使得每个 router 有自己的路由表,而且不会与其他 router 冲突,所以能很好地支持网络重叠。

 

六、openstack内部网络如何与外部网络通信

router 的每个 interface 在namespace 中都有对应的 veth。

如果 veth 用于连接租户网络,命名格式为 qr-xxx,比如 qr-d568ba1a-74 和 qr-e17162c5-00。

如果 veth 用于连接外部网络,命名格式为 qg-xxx,比如 qg-b8b32a88-03。

 

查看 router 的路由表信息。

openstack创建port流表 openstack创建网络_openstack_14

可以看到默认网关为10.10.10.1。

意味着对于访问vlan100 和 vlan101 租户网络以外的所有流量,router_100_101都将转发给 ext_net 的网关 10.10.10.1。

openstack创建port流表 openstack创建网络_网络_15

当数据包从 router 连接外网的接口 qg-b8b32a88-03 发出的时候,会做一次 Source NAT,即将包的源地址修改为 router 的接口地址 10.10.10.2,这样就能够保证目的端能够将应答的包发回给 router,然后再转发回源端 instance。

 

可以通过 iptables 命令查看 SNAT 的规则。

 

openstack创建port流表 openstack创建网络_IP_16

SNAT 让 instance 能够直接访问外网,但外网还不能直接访问 instance,因为 instance 没有外网 IP。

这里 “直接访问 instance” 是指通信连接由外网发起,例如从外网 SSH cirros-vm3。

 

七、floating ip浮动IP地址

当租户网络连接到 Neutron router,通常将 router 作为默认网关。 
当 router 接收到 instance 的数据包,并将其转发到外网时:

1. router 会修改包的源地址为自己的外网地址,这样确保数据包转发到外网,并能够从外网返回。

2. router 修改返回的数据包,并转发给真正的 instance。

这个行为被称作 Source NAT。

如果需要从外网直接访问 instance,则可以利用 floating IP。 
下面是关于 floating IP 必须知道的事实:

1. floating IP 提供静态 NAT 功能,建立外网IP 与 instance 租户网络 IP 的一对一映射。

2. floating IP 是配置在 router 提供网关的外网 interface 上的,而非 instance 中。

3. router 会根据通信的方向修改数据包的源或者目的地址。

floating IP 已经配置到 router 的外网 interface qg-b8b32a88-03 上。

查看 router 的 NAT 规则:

openstack创建port流表 openstack创建网络_openstack创建port流表_17

openstack创建port流表 openstack创建网络_IP_18

iptables 增加了两条处理 floating IP 的规则:

1. 当 router 接收到从外网发来的包,如果目的地址是 floating IP 10.10.10.3,将目的地址修改为 cirros-vm3 的 IP 172.16.101.3。这样外网的包就能送达到 cirros-vm3。

2. 当 cirros-vm3 发送数据到外网,源地址 172.16.101.3 将被修改为 floating IP 10.10.10.3。

小结一下:

1. floating IP 能够让外网直接访问租户网络中的 instance。这是通过在 router 上应用 iptalbes 的 NAT 规则实现的。

2. floating IP 是配置在 router 的外网interface 上的,而非 instance。