理解 neutron(15):Neutron Linux Bridge + VLAN/VXLAN 虛擬網絡


 

學習 Neutron 系列文章:

(1)Neutron 所實現的虛擬化網絡

(2)Neutron OpenvSwitch + VLAN 虛擬網絡

(3)Neutron OpenvSwitch + GRE/VxLAN 虛擬網絡

(4)Neutron OVS OpenFlow 流表 和 L2 Population

(5)Neutron DHCP Agent

(6)Neutron L3 Agent  

(7)Neutron LBaas

(8)Neutron Security Group

(9)Neutron FWaas 和 Nova Security Group

(10)Neutron VPNaas

(11)Neutron DVR

(12)Neutron VRRP

(13)High Availability (HA)

(14)Linux bridge + VXLAN

(15)Neutron Linux Bridge + VLAN/VXLAN 虛擬網絡

 

雖然大部分的OpenStack 部署環境中,都會使用 Open vSwitch 來作為虛擬交換機來實現二層網絡功能,但是Neutron 仍然支持使用 Linux bridge 作為虛擬交換機來實現二層網絡。本文就此做些分析和說明。 

同時要指出的是,OpenStack 官方已經把 linux bridge 實現標記為 legacy 的了,文檔從 2016 年后也沒怎么更新了。這是因為,linux bridge 和 OVS 相比,只支持基本的網絡功能即二層交換,但不支持VLAN 標簽和隧道。因此,linux bridge agent 利用linux 內核功能(VLAN 子接口和 VXLAN 接口)來實現VLAN 標簽和隧道。

 

 1. 測試環境

以下面的環境為例(網絡節點上):

(1)linux bridge

root@controller:/home/sammy# brctl show
bridge name     bridge id               STP enabled     interfaces
brq85925305-b4          8000.563534c8d02d       no              tap0bb8efeb-10
                                                        tap798c87d1-a2
                                                        vxlan-25
brq96609bfa-0e          8000.0050569c4d94       no              ens224
                                                        tap60dbdc2f-a0
brq971ffda2-e5          8000.a6acb08e4fd6       no              tapb1eaae00-e5
                                                        tapf70543dd-0f
                                                        vxlan-10

(2)OpenStack 網絡和 network namespace:

root@controller:/home/sammy# neutron net-list
+--------------------------------------+---------+-----------------------------------------------------+
| id                                   | name    | subnets                                             |
+--------------------------------------+---------+-----------------------------------------------------+
| 96609bfa-0e22-4bb7-8dba-6ef532ea6076 | extnet  | afa7d205-3026-439f-aca7-295a9f9b2a71 10.62.227.0/24 |
| 971ffda2-e567-40a0-a2c8-b31a577fd4d3 | appnet  | 4c68eacb-bf3e-408a-a941-94e93eddb22b 11.0.0.0/24    |
|                                      |         | 3d596991-de8f-4ae4-8913-89426a8abbd7 10.0.0.0/24    |
| 85925305-b477-4cc6-9654-67d9bf1e7cd8 | appnet2 | 4575c7f1-7f08-4917-9904-ec65af38619b 20.0.0.0/24    |
+--------------------------------------+---------+-----------------------------------------------------+
root@controller:/home/sammy# ip netns
qdhcp-85925305-b477-4cc6-9654-67d9bf1e7cd8 (id: 2)
qdhcp-971ffda2-e567-40a0-a2c8-b31a577fd4d3 (id: 1)
qrouter-39a77439-8a28-49c1-bf97-ac931510631b (id: 0)

(3)示意圖:

(4)說明:

  • qdhcp 和 qrouter 都是 linux network namespace 實例
  • qdhcp network namespace 的數量等於啟用了 DHCP 的 Neutron network 的數量。
    • 當一個 network 中存在至少一個 subnet 啟用了 DHCP 之后,會有一個 qdhcp network namespace 被創建出來;
    • 當一個 network 中多個 subnet 啟用了 DHCP 時,它們共用一個 qdhcp,以及 dnsmasq。
    • 其 name 使用 network id,比如 qdhcp-85925305-b477-4cc6-9654-67d9bf1e7cd8
  • qrouter network namespace 的數目等於 router 的數目,也就是說,系統中一共有幾個 router,那么就存在幾個 qrouter network namespace
  • brq linux bridge 的數目等於 neutron network 的數目,其 name 是 network id 的前幾位,比如 brq96609bfa-0e
  • 一個 network 的 qdhcp network namespace 和其 brq linux bridge 一定有連接
  • qrouter 之內的 network interface 分兩種,一種是 qr 開頭的,每個連接到 router 之上的 subnet 都有一個;還有一個是 qg,每個連接到 router 的 external subnetwork 有一個
  • qrouter 的每個 network interface 都通過 veth 連接到所在網絡的 qbr linux bridge 上
  • qbr linux bridge 連連接兩種物理設備,一種是 vxlan interface,每個 tenant network 有一個,另一種是在 physical network 對應的物理網卡上創建的子接口(sub-interface)
  • 對於 physical network 的 qbr 來說,用戶可以指定它,並且在linuxbridge_agent.ini 中通過 bridge_mappings = List of <physical_network>:<physical_bridge> 進行配置;也可以不指定,此時 agent 會創建它。當同時配置了 physical bridge 和 physical interface 時,前者優先。

如果 external network 中有多個 subnet 的話:

(1)每個 qrouter 只允許有一個 External Gateway,也就是說它只有一個 qg network interface。當 external network 添加多個 subnet 之后,只有第一個被當作 external subnet,其余的都會被當作 internal subnet。

(2)在 qrouter 的路由表之中,

root@controller:/home/sammy# ip netns exec qrouter-39a77439-8a28-49c1-bf97-ac931510631b route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         10.62.227.1     0.0.0.0         UG    0      0        0 qg-e09fce07-cd
10.0.0.0        *               255.255.255.0   U     0      0        0 qr-b1eaae00-e5
10.62.227.0     *               255.255.255.0   U     0      0        0 qg-e09fce07-cd
10.62.228.0     *               255.255.255.0   U     0      0        0 qg-e09fce07-cd
10.62.228.0     *               255.255.255.0   U     0      0        0 qr-124ff148-b7
11.0.0.0        *               255.255.255.0   U     0      0        0 qr-16d9b0cc-38
20.0.0.0        *               255.255.255.0   U     0      0        0 qr-0bb8efeb-10

 

2. linux-bridge-agent 工作過程分析

(1)linuxbridge-agent 會啟動一個循環,不斷掃描上面紅框中的 tap 設備

    def daemon_loop(self):
...
        while True:
            start = time.time()
. ..

            device_info = self.scan_devices(previous=device_info, sync=sync)
            sync = False

            if (self._device_info_has_changes(device_info)
                or self.sg_agent.firewall_refresh_needed()):
                LOG.debug("Agent loop found changes! %s", device_info)
                try:
                    sync = self.process_network_devices(device_info)
                except Exception:
                    LOG.exception(_LE("Error in agent loop. Devices info: %s"),
                                  device_info)
                    sync = True

這是它首先找到的 devices:

(Pdb) p bridge_lib.get_bridge_names()
['brq85925305-b4', 'virbr0', 'brq971ffda2-e5', 'virbr0-nic', 'tapb1eaae00-e5', 'tapf70543dd-0f', 'vxlan-25', 'vxlan-10', 'tap0bb8efeb-10', 'lo', 'tap60dbdc2f-a0', 'tap795e6e86-94', 'ens224', 'ens192', 'ens160', 'tap798c87d1-a2']

然后過濾出 tap 設備:

get_all_devices()->set(['tap0bb8efeb-10', 'tap60dbdc2f-a0', 'tap795e6e86-94', 'tap798c87d1-a2', 'tapb1eaae00-e5', 'tapf70543dd-0f'])

(2)根據 previous 中保存的歷史數據,再接合服務器端和本地更新時間,計算出需要更新的tap設備列表:

{'current': set(['tapf70543dd-0f', 'tap60dbdc2f-a0', 'tapb1eaae00-e5', 'tap795e6e86-94', 'tap0bb8efeb-10', 'tap798c87d1-a2']), 'timestamps': {'tapf70543dd-0f': 1476956816.672447, 'tap60dbdc2f-a0': None, 'tapb1eaae00-e5': 1476956816.672447, 'tap795e6e86-94': None, 'tap0bb8efeb-10': 1476689797.1378036, 'tap798c87d1-a2': 1476689701.1349163}, 'removed': set([]), 'added': set(['tapf70543dd-0f', 'tap60dbdc2f-a0', 'tapb1eaae00-e5', 'tap795e6e86-94', 'tap0bb8efeb-10', 'tap798c87d1-a2']), 'updated': set([])}

  (3) 通過 RPC 獲取 tap 設備的詳細信息

(Pdb) p devices
set(['tapf70543dd-0f', 'tap60dbdc2f-a0', 'tapb1eaae00-e5', 'tap795e6e86-94', 'tap798c87d1-a2', 'tap0bb8efeb-10'])


devices_details_list = self.plugin_rpc.get_devices_details_list

(Pdb) p devices_details_list
[{u'profile': {}, u'network_qos_policy_id': None, u'qos_policy_id': None, u'allowed_address_pairs': [], u'admin_state_up': True, u'network_id': u'971ffda2-e567-40a0-a2c8-b31a577fd4d3', u'segmentation_id': 10, u'device_owner': u'network:dhcp', u'physical_network': None, u'mac_address': u'fa:16:3e:5c:bf:11', u'device': u'tapf70543dd-0f', u'port_security_enabled': False, u'port_id': u'f70543dd-0f1b-4e1d-93c7-33f4f3d7a709', u'fixed_ips': [{u'subnet_id': u'3d596991-de8f-4ae4-8913-89426a8abbd7', u'ip_address': u'10.0.0.10'}], u'network_type': u'vxlan', u'security_groups': []}, {u'profile': {}, u'network_qos_policy_id': None, u'qos_policy_id': None, u'allowed_address_pairs': [], u'admin_state_up': True, u'network_id': u'96609bfa-0e22-4bb7-8dba-6ef532ea6076', u'segmentation_id': None, u'device_owner': u'network:router_gateway', u'physical_network': u'provider', u'mac_address': u'fa:16:3e:77:78:86', u'device': u'tap60dbdc2f-a0', u'port_security_enabled': False, u'port_id': u'60dbdc2f-a01b-446d-bb5b-26ffac19a045', u'fixed_ips': [{u'subnet_id': u'afa7d205-3026-439f-aca7-295a9f9b2a71', u'ip_address': u'10.62.227.151'}], u'network_type': u'flat', u'security_groups': []}, {u'profile': {}, u'network_qos_policy_id': None, u'qos_policy_id': None, u'allowed_address_pairs': [], u'admin_state_up': True, u'network_id': u'971ffda2-e567-40a0-a2c8-b31a577fd4d3', u'segmentation_id': 10, u'device_owner': u'network:router_interface', u'physical_network': None, u'mac_address': u'fa:16:3e:81:1b:37', u'device': u'tapb1eaae00-e5', u'port_security_enabled': False, u'port_id': u'b1eaae00-e504-41f8-93a4-643687155bea', u'fixed_ips': [{u'subnet_id': u'3d596991-de8f-4ae4-8913-89426a8abbd7', u'ip_address': u'10.0.0.1'}], u'network_type': u'vxlan', u'security_groups': []}, {u'profile': {}, u'network_qos_policy_id': None, u'qos_policy_id': None, u'allowed_address_pairs': [], u'admin_state_up': True, u'network_id': u'96609bfa-0e22-4bb7-8dba-6ef532ea6076', u'segmentation_id': None, u'device_owner': u'network:dhcp', u'physical_network': u'provider', u'mac_address': u'fa:16:3e:5f:94:7d', u'device': u'tap795e6e86-94', u'port_security_enabled': False, u'port_id': u'795e6e86-94af-4b72-ae1a-5a324a017774', u'fixed_ips': [{u'subnet_id': u'afa7d205-3026-439f-aca7-295a9f9b2a71', u'ip_address': u'10.62.227.150'}], u'network_type': u'flat', u'security_groups': []}, {u'profile': {}, u'network_qos_policy_id': None, u'qos_policy_id': None, u'allowed_address_pairs': [], u'admin_state_up': True, u'network_id': u'85925305-b477-4cc6-9654-67d9bf1e7cd8', u'segmentation_id': 25, u'device_owner': u'network:dhcp', u'physical_network': None, u'mac_address': u'fa:16:3e:25:27:99', u'device': u'tap798c87d1-a2', u'port_security_enabled': False, u'port_id': u'798c87d1-a2d8-4df7-b7fc-5ab30918a0de', u'fixed_ips': [{u'subnet_id': u'4575c7f1-7f08-4917-9904-ec65af38619b', u'ip_address': u'20.0.0.100'}], u'network_type': u'vxlan', u'security_groups': []}, {u'profile': {}, u'network_qos_policy_id': None, u'qos_policy_id': None, u'allowed_address_pairs': [], u'admin_state_up': True, u'network_id': u'85925305-b477-4cc6-9654-67d9bf1e7cd8', u'segmentation_id': 25, u'device_owner': u'network:router_interface', u'physical_network': None, u'mac_address': u'fa:16:3e:9f:18:a9', u'device': u'tap0bb8efeb-10', u'port_security_enabled': False, u'port_id': u'0bb8efeb-108f-409a-82e7-c4c20f0d4f69', u'fixed_ips': [{u'subnet_id': u'4575c7f1-7f08-4917-9904-ec65af38619b', u'ip_address': u'20.0.0.1'}], u'network_type': u'vxlan', u'security_groups': []}]

(4) 對需要處理的設備,調用 self.process_network_devices(device_info) 函數進行處理

(5). 調用 plug_interface

interface_plugged = self.mgr.plug_interface(network_id, segment,device, device_details['device_owner'])

(6). 需要的話,使用已經配置的或者新建 linux brige,並將 physical interface 設備加入其中

bridge_name = self.get_existing_bridge_name(physical_network) #獲取為 physical network 配置的 linux bridge
bridge_name = self.get_bridge_name(network_id) #或者根據 network id 生成 bridge name

(7).根據不同的網絡類型,分別處理 vxlan bridge,flat bridge 和 vlan bridge

    def ensure_physical_in_bridge(self, network_id,
                                  network_type,
                                  physical_network,
                                  segmentation_id):
        if network_type == p_const.TYPE_VXLAN:
            if self.vxlan_mode == lconst.VXLAN_NONE:
                LOG.error(_LE("Unable to add vxlan interface for network %s"),
                          network_id)
                return
            return self.ensure_vxlan_bridge(network_id, segmentation_id)

        # NOTE(nick-ma-z): Obtain mappings of physical bridge and interfaces
        physical_bridge = self.get_existing_bridge_name(physical_network)
        physical_interface = self.interface_mappings.get(physical_network)
        if not physical_bridge and not physical_interface:
            LOG.error(_LE("No bridge or interface mappings"
                          " for physical network %s"),
                      physical_network)
            return
        if network_type == p_const.TYPE_FLAT:
            return self.ensure_flat_bridge(network_id, physical_bridge,
                                           physical_interface)
        elif network_type == p_const.TYPE_VLAN:
            return self.ensure_vlan_bridge(network_id, physical_bridge,
                                           physical_interface,
                                           segmentation_id)

對於 flat 類型的網絡,調用 ensure_physical_in_bridge

def ensure_physical_in_bridge(self, network_id,network_type,physical_network,segmentation_id)
  if network_type == p_const.TYPE_FLAT:
    return self.ensure_flat_bridge(network_id, physical_bridge,physical_interface)

如果有配置 physical bridge 的話,使用它;否則創建 bridge,並將物理網卡配置的 ip 地址和 gateway 從網卡挪到 linux bridge

def ensure_flat_bridge(self, network_id, phy_bridge_name,physical_interface):
  """Create a non-vlan bridge unless it already exists."""
  if phy_bridge_name:
    return self.ensure_bridge(phy_bridge_name) #獲取預先配置好的 linux bridge   else:
    bridge_name = self.get_bridge_name(network_id)
    ips, gateway = self.get_interface_details(physical_interface)
    if self.ensure_bridge(bridge_name, physical_interface, ips,gateway): #創建 bridge     return physical_interface

對於 vxlan 類型的 network,需要創建 vxlan interface

    def ensure_vxlan_bridge(self, network_id, segmentation_id):
        """Create a vxlan and bridge unless they already exist."""
        interface = self.ensure_vxlan(segmentation_id)
        if not interface:
            LOG.error(_LE("Failed creating vxlan interface for "
                          "%(segmentation_id)s"),
                      {segmentation_id: segmentation_id})
            return
        bridge_name = self.get_bridge_name(network_id)
        self.ensure_bridge(bridge_name, interface)
        return interface

創建 vxlan interface:

    def ensure_vxlan(self, segmentation_id):
        """Create a vxlan unless it already exists."""
        interface = self.get_vxlan_device_name(segmentation_id)
        if not ip_lib.device_exists(interface):
            LOG.debug("Creating vxlan interface %(interface)s for "
                      "VNI %(segmentation_id)s",
                      {'interface': interface,
                       'segmentation_id': segmentation_id})
            args = {'dev': self.local_int}
            if self.vxlan_mode == lconst.VXLAN_MCAST:
                args['group'] = self.get_vxlan_group(segmentation_id)
            if cfg.CONF.VXLAN.ttl:
                args['ttl'] = cfg.CONF.VXLAN.ttl
            if cfg.CONF.VXLAN.tos:
                args['tos'] = cfg.CONF.VXLAN.tos
            if cfg.CONF.VXLAN.l2_population:
                args['proxy'] = cfg.CONF.VXLAN.arp_responder
            try:
                int_vxlan = self.ip.add_vxlan(interface, segmentation_id,
                                              **args)

(8). 將 tap 設備加入到 linux bridge 中

bridge_lib.BridgeDevice(bridge_name).addif(tap_device_name)

(9). 如果將一個 tap 設備被刪除,那么 linux-bridge-agent 會發現:

2016-10-26 10:29:58.347 30219 INFO neutron.agent.securitygroups_rpc [req-e3264065-6414-4b5a-8d2b-dfafad6fdde8 - - - - -] Remove device filter for set(['tap60dbdc2f-a0'])
2016-10-26 10:29:58.433 30219 INFO neutron.plugins.ml2.drivers.agent._common_agent [req-e3264065-6414-4b5a-8d2b-dfafad6fdde8 - - - - -] Attachment tap60dbdc2f-a0 removed
2016-10-26 10:29:58.536 30219 INFO neutron.plugins.ml2.drivers.agent._common_agent [req-e3264065-6414-4b5a-8d2b-dfafad6fdde8 - - - - -] Port tap60dbdc2f-a0 updated.

3. 關於上述工作過程的簡單結論

3.1 簡單結論

  1. l3agent 和 dhcpagent 創建 network namespace 時創建 tap 設備,和 network namespace 中的 interface 是一對 veth pair。當手工刪除 tap 設備時,相應的 veth endpoint 也會被刪除。
  2. linuxbridgeagent 不斷掃描服務器端和本地的 tap 設備
  3. linuxbridgeagent 獲取需要增加和修改的tap設備列表
  4. 對於需要增加的 tap 設備,獲取其詳細信息,主要是 network_id,network_type,physical_network,segmentation_id,device_owner 等,然后根據這些信息,創建 linux bridge,並加入所需要的 interface
  5. 創建所需要的 linux bridge,並將 physical interface (provider network 的 physical interface 或者 tenant network 的 vxlan interface)加入 bridge,並且將 tap 設備也加入該 bridge
  6. 如果發現某個 linux bridge 沒有創建出來,首先需要查看有沒有相應的 tap 設備存在;如果 tap 設備不存在,則查看相應的 qdhcp 或者 qrouter 中時候有interface

 

具有多個 VLAN 租戶網絡時候的網絡元素示意圖:

 

 

 3.2 關於 unnumber interface

OpenStack 官方的 host networking 配置中,連接外網的 interface 可以是 unnumbered 的,從字面意思理解,就是該 interface 上不需要配置 IP 地址。

配置的時候,修改 /etc/network/interfaces:

# The provider network interface
auto ens224
iface ens224 inet manual
up ip link set dev $IFACE up
down ip link set dev $IFACE down

配置好以后:

root@controller:/home/sammy# ifconfig ens224
ens224    Link encap:Ethernet  HWaddr 00:50:56:9c:4d:94
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:27300737 errors:0 dropped:0 overruns:0 frame:0
          TX packets:61547 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:31951077598 (31.9 GB)  TX bytes:5966060 (5.9 MB)

root@controller:/home/sammy# ifconfig brq96609bfa-0e
brq96609bfa-0e Link encap:Ethernet  HWaddr 00:50:56:9c:4d:94
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:32855 errors:0 dropped:0 overruns:0 frame:0
          TX packets:2 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:2731030 (2.7 MB)  TX bytes:84 (84.0 B)

具體原理不詳,但是應該是因為 qrouter 的 qg network interface 和物理網絡中的路由器的網卡之間是網絡二層,因此中間的設備都是屬於二層的,因此不需要處於網絡三層的 IP 地址。

4. 使用 linux bridge 時的拓撲結構

4.1 網絡節點上

為了更清楚,我們來對比着看 linux bridge 和 ovs 的兩種方案:

linux 方案:

 

網絡服務:

  • Linux bridge agent
  • L3 agent
  • DHCP agent
  • Metadata agent

Linux bridge agent 會為每個 VLAN 虛擬網絡創建一個 VLAN Bridge,它連接多個網元:

  • VLAN 子接口,從物理網卡(圖中的 interface3)上創建,每個子接口對應一個VLAN ID,其名稱格式為 device.sid,其中 device 是物理網卡名字比如 eth0,sid 是 vlan id。
  • 連接虛擬機的 tap 接口
  • 和 qrouter 連接的 tap 接口
  • 和該網絡的 qdhcp 連接的 tap 接口

如果同時有 VXLAN 虛擬網絡的話(linux-bridge 不支持GRE 隧道模式),會為每個 VLAN 虛擬網絡創建一個 Tunnel bridge。它連接多個網元:

  • vxlan interface,這種接口每個虛擬網絡一個,名字格式為 vxlan-sid,其中 sid 是分段ID。
  • 連接虛擬機的 tap 接口
  • 和 qrouter 連接的 tap 接口
  • 和該網絡的 qdhcp 連接的 tap 接口

安全組規則在 tunnel bridge 和 vlan bridge 上。

OVS 方案:

這里面,br-int 會負責加本地 VLAN 標簽,br-tun 會負責將 VLAN ID 轉換為 VXLAN ID。

 

4.2 計算節點上

同樣來對比着看。

linux bridge:

網絡服務:

  • Linux bridge agent

和網絡節點類似,只不過沒有 qrouter 和 qdhcp,不在贅述。

OVS:

 

OVS 放在在 br-int 上實現 VLAN 標簽,在 br-tun 上實現隧道,在 qbr linux bridge 上實現安全組。

 

4.3 網絡路徑 - 南北向網絡流向

VLAN 網絡和VXLAN 網絡井水不犯河水。這圖上的配置中,計算節點和網絡節點上的物理網卡都分開了。

4.4 網絡路徑 - 東西向(不同網絡)

4.5 網絡路徑 - 東西向(同一個網絡)

 

請詳細說明和配置,請參閱參考文檔。

5. 一點結論

和基於 OVS 的二層網絡相比,

  • 功能和架構上:基於 linux bridge 的實現還是有一些短處,比如每個虛擬網絡就需要一個網橋,這在大規模環境中會帶領資源使用和管理上的問題。其好處是本身架構比較清晰。
  • 性能上:基本上差不多,如下圖所示,不管是 vxlan 還是 vlan。

 參考資料:

歡迎大家關注我的個人公眾號:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM