Netruon 理解(12):使用 Linux bridge 將 Linux network namespace 連接外網


學習 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)使用 NAT 將 Linux network namespace 連接外網

(15)使用 Linux bridge 將 Linux network namespace 連接外網

 

 前一篇文章介紹了使用 NAT 將 Linux network namespace 連接外網,但是這種模式有很大的局限,包括它使用的是內部IP,因此,外部計算機不能直接訪問其IP,而需要通過訪問其主機再通過 DNAT 才能訪問它。它的應用場景通常是因為企業使用的公網IP地址一般都數量有限,在內部計算機需要訪問公網時,往往采取 NAT 方式。本文將介紹使用 linux bridge 來將 linux network namespace 連接到外網。

1. 環境及配置

1.1 測試環境

(圖1)

環境說明:

  • 計算機1(host1)是一個在 ESXi 上的 VMware 虛機,它擁有兩塊網卡,其中 eth0 用於與計算機2(host2)通信。
  • host1 的 IP 地址為 192.168.1.87. 實驗使用的另一個機器 host2 的 IP 為 192.168.1.48. 它們的網關為 192.168.1.1
  • host1 上的 /proc/sys/net/ipv4/ip_forward 內容為0,也就是說 ip forwarding 是關閉的
  • host1 上的 iptables filter 表:
root@linuxkvm1:/etc# iptables -t filter -S
-P INPUT ACCEPT
-P FORWARD DROP
-P OUTPUT ACCEPT

為了能從在 host1 上的 netns ns2 上能 ping 通 host2 ,你需要做的配置及說明:

步驟# 命令 說明
1 ip netns add ns2 創建名稱為 ‘ns2’ 的 linux network namespace
2 ip link add veth1 type veth peer name veth2 創建一個 veth 設備,一頭為 veth1,另一頭為 veth2
3 ip link set veth2 netns ns2 將 veth2 加入 ns2 作為其一個 network interface
4

brctl addbr br1

brctl addif br1 eth0

ifconfig eth0 0.0.0.0

ifconfig br1 192.168.1.87/24 up

brctl addif br1 veth1

創建 liux bridge ‘br1’

刪除 eth0 的 IP 地址,並將其地址設給 br1

將 eth0 加入 br1

將 veth1 加入 br1

5 ip netns exec ns2 ifconfig veth2 192.168.1.88/24 up 配置 veth2 的 IP 地址,它和 host1 和 host2 在同一個網段上
6 ip netns exec ns2 route add default gw 192.168.1.1 將 ns2 的默認路由設為 host1 和 host2 的網關地址
7

iptables -t filter  -A FORWARD -m physdev --physdev-in eth0 --physdev-out veth1 -j ACCEPT

iptables -t filter  -A FORWARD -m physdev --physdev-out eth0 --physdev-in veth1 -j ACCEPT

設置 FORWARD 規則

做了以上配置之后,

  • 從ns2 中可以ping 其它的計算機,無論是 192.168.1.0 網段還是其它網段
  • 從其他計算機上可以ping 192.168.1.88

備注:請確保所有 network interface 都是出於 up 狀態,可以使用 ifconfig 命令查看其狀態,如果是 down 的話可以使用 ip link set <interface> up 來設置。

2. 原理

2.1 linux bridge forwarding

當從外部計算機 ping veth2 的 IP 地址時的 iptables 統計:

Chain INPUT (policy ACCEPT 1814 packets, 198K bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain FORWARD (policy DROP 116 packets, 7950 bytes)
 pkts bytes target     prot opt in     out     source               destination
  154 11794 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            PHYSDEV match --physdev-in ens9f0 --physdev-out veth1
  121  8724 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            PHYSDEV match --physdev-in veth1 --physdev-out ens9f0

Chain OUTPUT (policy ACCEPT 2014 packets, 184K bytes)
 pkts bytes target     prot opt in     out     source               destination

說明網絡流量確實經過了 linux bridge 做 forwarding。關於 linux bridge 上的 iptables 設置的說明的更詳細內容,請參考 ebtables/iptables interaction on a Linux-based bridge。要點包括:

    • 跟 linux bridge 相關的有 iptables 和 ebtables 過濾表
    • linux 內核 2.6 版本包含了 ebtables 和 br-nf 的代碼,其中 br-nf 代碼使得被 bridge 的網絡幀/包會經過 iptables 過濾表;ebtables 表工作在網絡二層(Ethernet),iptables 表工作在上層(IP)。
    • 當一個 IP 包進入了一個 bridge/router interface 后,它將網絡包發給另一個 bridge interface的情形如下:
    • (圖2)
    • 當一個 IP 包進入了一個 bridge/router interface 后,它將網絡包發給一個非 bridge interface的情形如下:
      • (圖3)

基於上面的原理,就本文中的案例的要求,

(1)如果使用 physdev 模塊的話,可以使用下面兩條規則進行精准的控制:

iptables -t filter  -A FORWARD -m physdev --physdev-in eth0 --physdev-out veth1 -j ACCEPT
iptables -t filter  -A FORWARD -m physdev --physdev-out eth0 --physdev-in veth1 -j ACCEPT

備注:

  • physdev-in 指定的是網絡包進入的 bridge 的端口
  • physdev-out 指定的是網絡包離開的 bridge 的端口

(2)也可以使用常規規則來控制是否允許 br1 進行 forwarding

iptables -t filter -A FORWARD -i br1 -j ACCEPT

(3)linux 內核的 ip forwrading 不需要啟用,它主要針對的是 NAT 情形。

2.2 linux bridge 的轉發行為

Linux bridge 根據收到的幀的目的 MAC 地址來決定其行為:

  • 如果幀的目的 MAC 地址是已知的在 bridge 的另一頭,會做 bridging (轉發)
  • 如果幀的目的 MAC 地址是未知的,會做 flooding (泛洪)
  • 如果幀的目的 MAC 地址是 bridge 自身或者它的某個端口的 MAC 地址(local),則發往上層 IP 層
  • 如果目的 MAC 地址是已知的而且在 bridge 的源側,則丟棄

linux bridge 自身維護了 mac 地址和輸入端口的映射表:

root@linuxkvm1:/home/s1# brctl showmacs br-ens9f0
port no mac addr                is local?       ageing timer
  1     30:0e:d5:c6:17:25       no               224.96
  2     7e:60:30:bb:21:93       yes                0.00
  2     7e:60:30:bb:21:93       yes                0.00
  1     a0:36:9f:5c:93:f8       no                58.07
  1     a0:36:9f:97:b1:68       yes                0.00
  1     a0:36:9f:97:b1:68       yes                0.00
  2     ee:67:31:cc:49:11       no                 0.29
  • 當從 ns2 中 ping 外部計算機時,因為 bridge 發現其目的 mac 地址不是 local 的,它對該 IP 包執行 linux bridging,這就會觸發 2.1 中討論過的過濾規則。
  • 當從 ns2 中 ping host1 時,因為目的 mac 地址是 local 的,它會直接把它發給 IP 層,此時,前面討論的 FORWARD 鏈的 filter 表的兩條過濾規則對它不起作用,這也就是為什么即使不添加這兩天規則,ping host1 也是會成功的。

 2.3 網絡接口的混雜模式(Promiscuous mode, 簡稱 Promisc mode)

   根據 wikipedia 的定義,Promisc 模式是指一個 NIC 會把它接受的所有網絡流量都交給 CPU,而不是只是把它想轉交的部分交給 CPU。在 IEEE 802 網絡中,每個網絡幀都有一個目的 MAC 地址。在 non-promiscuous 模式下,NIC 只會接受目的 MAC 地址是它自己的 MAC 地址的單播幀,以及多播及廣播幀。在混雜模式下,NIC 會接受經過它的所有幀。

   簡單地,你可以使用 ifconfig 命令或者 netstat -i 命令來查看一個 network interface 上的混雜模式是否打開了:

  • ifconfig eth0, 查看 eth0 的配置,包括混雜模式。當輸出包含 PRMISC 時,表明該網絡接口處於混雜模式。但是也有特殊情況,參見下面的 2.3.2 部分。
root@linuxkvm1:/home/s1# ifconfig eth0
eth0      Link encap:Ethernet  HWaddr a0:36:9f:97:b1:68
          inet6 addr: fe80::a236:9fff:fe97:b168/64 Scope:Link
          UP BROADCAST RUNNING PROMISC MULTICAST  MTU:1500  Metric:1
  • ifconfig eth0 promisc  //使 eth0 進入混雜模式
  • ifconfig eth0 -promisc //使 eth0 退出混雜模式

本例中,經過 eth0 的網絡流量,既包括發給它的,也包括發給 ns2 的,此時幀的目的 MAC 地址不再是 eth0 自己的MAC地址,因此,eth0 的混雜模式必須打開。但是,在測試過程中,發現兩個有意思的事情。

2.3.1 VMware 虛機的 NIC 的混雜模式

根據 How promiscuous mode works at the virtual switch and portgroup levels 這篇文章,VMware 虛機的 NIC 需要啟用混雜模式時,VMware vSwitch 以及它的 Virtual group 中的 vPort 也需要開啟混雜模式。當 vSwitch 啟用了混雜模式時,它上面的所有端口組(portgroup)也默認開啟了混雜模式。好吧,在我的測試中,為了找到這個問題,花了我不少時間。

(1)開啟 vSwitch 的混雜模式

(2)端口組的混雜模式,默認是隨 vSwitch 的混雜模式,但是你也可以顯式地打開或者關閉

2.3.2 VirtualBox 虛機網卡的混雜模式

2.3.3 linux bridge 及其接口的混雜模式

測試過程發現,當一個網絡接口被加入了 linux bridge 之后,它的混雜模式就會被自動開啟,而且無法關閉,直到把它從 bridge 上刪除。

(1)當 veth 設備離開 linux bridge 后,自動退出混雜模式

brctl delif br-ens9f0 veth40
dmesg | grep promiscuous
[498665.637647] device veth40 left promiscuous mode

此時可以手工設置其 promisc 模式了:

root@linuxkvm1:/home/s1# netstat -i | grep veth40
veth40 1500 0 68386 0 0 0 280670 0 0 0 BMRU
root@linuxkvm1:/home/s1# ifconfig veth40 promisc
root@linuxkvm1:/home/s1# netstat -i | grep veth40
veth40 1500 0 68386 0 0 0 280670 0 0 0 BMPRU
[498822.803260] device veth40 entered promiscuous mode

(2)當 veth 設備被加入 linux bridge 后,自動進入 promisc 模式

brctl addif br-ens9f0 veth40
dmesg | grep promiscuous
[498681.199680] device veth40 entered promiscuous mode

此時即使通過ifconfig 將其設置為非 promisc 模式,netstat -i 也顯示其處於非 promis 模式,但是其實此時它仍然處於 promisc 模式:

 
         
dmesg沒有記錄
root@linuxkvm1:/home/s1# ifconfig veth40 -promisc 
root@linuxkvm1:
/home/s1# netstat -i | grep veth40
veth40
1500 0 68410 0 0 0 280723 0 0 0 BMRU

結論:

  • 網絡設備被加入 linux bridge 后,自動進入混雜模式,而且無法退出。應該說這種做法也簡化了 linux bridge 環境中的網絡配置。
  • 網絡設備從 linux bridge 移出后,自動退出混雜模式,而且可以修改
  • linux bridge 自身也是一種二層網絡設備,但是它沒有混雜模式的說法,它會根據情況來轉發或者泛洪網絡幀

 

備注:本文所涉及的 linux bridge 以及 iptables 的相關知識比較復雜,本文作者僅確認本文中的測試過程及結果,原理分析部分可能存在錯誤。本文會保持持續更新。

 


免責聲明!

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



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