Contents

實作指南:使用 Linux Bridge 連接虛擬網路與設備

最近我需要讓 KVM 不透過設定路由,而是直接連接到現有網段。因此,我進一步研究網路新手虛擬網路設備 veth pair 實作筆記 - 程式狂想筆記這篇文章的主題。在這裡,我將簡單介紹如何操作 Linux Bridge,讓多種端口可以互相連接。

Info
最後,我有在虛擬家設定橋接外面路由。詳細可以參考這篇:

我參考了這篇文章 Linux Bridge 详解 | 没有理想的人不伤心,並在 Ubuntu 上成功實作。然而,我發現大多數的 Linux 系統並未預裝 bridge-utils。另外,iproute2 似乎也能用來設定 Bridge,我將嘗試使用不同的指令來進行設定。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# 新增網橋
# 原方法: brctl addbr br0
ip link add name br0 type bridge
# 啟動網橋
ip link set br0 up

# 新增三個netns
ip netns add ns0
ip netns add ns1
ip netns add ns2

# 新增兩對veth
ip link add veth0-ns type veth peer name veth0-br
ip link add veth1-ns type veth peer name veth1-br
ip link add veth2-ns type veth peer name veth2-br

# 將veth的一端移動到netns中
ip link set veth0-ns netns ns0
ip link set veth1-ns netns ns1
ip link set veth2-ns netns ns2

# 將netns中的本地環回和veth啟動並組態IP
ip netns exec ns0 ip link set lo up
ip netns exec ns0 ip link set veth0-ns up
ip netns exec ns0 ip addr add 10.0.0.1/24 dev veth0-ns

ip netns exec ns1 ip link set lo up
ip netns exec ns1 ip link set veth1-ns up
ip netns exec ns1 ip addr add 10.0.0.2/24 dev veth1-ns

ip netns exec ns2 ip link set lo up
ip netns exec ns2 ip link set veth2-ns up
ip netns exec ns2 ip addr add 10.0.0.3/24 dev veth2-ns

# 將veth的另一端啟動並掛載到網橋上
ip link set veth0-br up
ip link set veth1-br up
ip link set veth2-br up
# brctl addif br0 veth0-br
ip link set veth0-br master br0
# brctl addif br0 veth1-br
ip link set veth1-br master br0
# brctl addif br0 veth2-br
ip link set veth2-br master br0

在這裡,我不會詳細介紹 bridge 的概念。如果你想了解更多,可以參考我之前寫的文章。閱讀完這篇文章後,你應該能理解 Bridge 的原理以及需要注意的問題。

指令解說

安裝路由工具

這裡將說明兩種工具的安裝方法。如果你選擇使用較新的 iproute2,通常 Ubuntu 不需要再額外安裝這套軟體。

  • iproute2
1
2
sudo apt-get update
sudo apt-get install -y iproute2

以下是較舊的方法。

  • bridge-utils
1
2
sudo apt-get update
sudo apt-get install -y bridge-utils

新增網橋

bridge-utils 提供了 brctl 來控制 bridge 的操作。在這裡,brctl 的組合可以被理解為 bridge control

1
2
# <name> 放 bridge 名稱
brctl addbr <name>

新方法使用 ip link help 看相關指令。這些指令相當多,如果你不確定如何使用,建議可以參考範例。

1
2
3
4
5
6
7
8
9
root@primary:~# ip link help
Usage: ip link add [link DEV | parentdev NAME] [ name ] NAME
                    [ txqueuelen PACKETS ]
                    [ address LLADDR ]
                    [ broadcast LLADDR ]
                    [ mtu MTU ] [index IDX ]
                    [ numtxqueues QUEUE_COUNT ]
                    [ numrxqueues QUEUE_COUNT ]
                    type TYPE [ ARGS ]
1
2
# br_name 放 bridge 名稱
ip link add name <br_name> type bridge
Info

以下是一些 brctl 相關指令。如果你不小心設定錯誤,可以使用這些指令來還原設定。不過,重開機後設定也會被還原。

1
2
3
4
5
6
# show 顯示 bridge 資訊
brctl show <name>
# 刪除 bridge
brctl delbr <name>
# 顯示全部 bridge
brctl show

新增兩對veth

  • ip link add veth0-ns type veth peer name veth0-br

這段指令可能看起來有些複雜。我們可以透過 help 來查看詳細的使用方法。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
root@primary:~# ip link help
Usage: ip link add [link DEV | parentdev NAME] [ name ] NAME
                    [ txqueuelen PACKETS ]
                    [ address LLADDR ]
                    [ broadcast LLADDR ]
                    [ mtu MTU ] [index IDX ]
                    [ numtxqueues QUEUE_COUNT ]
                    [ numrxqueues QUEUE_COUNT ]
                    type TYPE [ ARGS ]

root@primary:~# ip link help veth
Usage: ip link <options> type veth [peer <options>]
To get <options> type 'ip link add help'

這邊我們看name也可以省略,如果從ip link <options> type veth [peer <options>]來看,你會發現可以省略更多東西。最後指令可以下ip link add type veth,只是 veth 建立出來會是系統幫你命名。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
ubuntu@primary:~$ sudo ip link add type veth
ubuntu@primary:~$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
.....
3: veth0@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether ca:f3:02:de:74:7e brd ff:ff:ff:ff:ff:ff
4: veth1@veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 92:83:9e:54:a5:90 brd ff:ff:ff:ff:ff:ff

將veth的一端移動到netns中

1
ip link set veth0-ns netns ns0
1
2
3
4
5
6
7
8
root@primary:~# ip link set help
...
ip link set { DEVICE | dev DEVICE | group DEVGROUP }
                        [ { up | down } ]
                        [ type TYPE ARGS ]
                ....
                [ netns { PID | NAME } ]
                ...

將netns中的本地環回和veth啟動並組態IP

1
2
3
# ip netns exec ns2 ip addr add 10.0.0.3/24 dev veth2-ns
# 這邊就不寫出 netns 指令出來
ip addr add 10.0.0.3/24 dev veth2-ns
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
ubuntu@primary:~$ ip addr help
Usage: ip address {add|change|replace} IFADDR dev IFNAME [ LIFETIME ]
                                                      [ CONFFLAG-LIST ]
       ip address del IFADDR dev IFNAME [mngtmpaddr]
       ip address {save|flush} [ dev IFNAME ] [ scope SCOPE-ID ]
                            [ to PREFIX ] [ FLAG-LIST ] [ label LABEL ] [up]
       ip address [ show [ dev IFNAME ] [ scope SCOPE-ID ] [ master DEVICE ]
                         [ type TYPE ] [ to PREFIX ] [ FLAG-LIST ]
                         [ label LABEL ] [up] [ vrf NAME ] ]
       ip address {showdump|restore}
IFADDR := PREFIX | ADDR peer PREFIX
          [ broadcast ADDR ] [ anycast ADDR ]
          [ label IFNAME ] [ scope SCOPE-ID ] [ metric METRIC ]
SCOPE-ID := [ host | link | global | NUMBER ]
FLAG-LIST := [ FLAG-LIST ] FLAG
FLAG  := [ permanent | dynamic | secondary | primary |
           [-]tentative | [-]deprecated | [-]dadfailed | temporary |
           CONFFLAG-LIST ]
CONFFLAG-LIST := [ CONFFLAG-LIST ] CONFFLAG
CONFFLAG  := [ home | nodad | mngtmpaddr | noprefixroute | autojoin ]
LIFETIME := [ valid_lft LFT ] [ preferred_lft LFT ]
LFT := forever | SECONDS

這邊可以看到 add

Tip
如果你需要刪除 Bridge,你需要先將所有的設備從 Bridge 中移除,然後再刪除 Bridge。你可以使用 brctl delif <bridge> <device> 或 ip link set <device> nomaster 來移除設備,然後使用 brctl delbr <bridge> 或 ip link delete <bridge> type bridge 來刪除 Bridge。

將veth的另一端啟動並掛載到網橋上

1
ip link set veth0-br master br0

從這指令看到中間用 master 字眼做串接

1
2
3
4
5
        ip link set { DEVICE | dev DEVICE | group DEVGROUP }
                        [ { up | down } ]
                        [ type TYPE ARGS ]
.....
                [ master DEVICE ][ vrf NAME ]
Info

加分題:將主機連接到 br0

你做到這邊會發現你 host 主機沒辦法連這些 IP ,假如你都會操作設定br0了,你應該也能設定。這邊可以自己試試看。

設定 br0

加分題:將主機連接到 br0

1
ip addr add  10.0.0.4/24 dev br0

完成這個步驟後,你應該就能進行連接了。

額外建立 veth pair 相連

1
2
3
4
5
ip link add  name veth-3 type veth peer name veth-br3
ip link set veth-br3 master br0
ip addr add 10.0.0.4/24 dev veth3
ip link set veth-3 up
ip link set veth-br3 up

完成這些設定後,你應該就能進行 ping 測試了。

1
2
3
4
root@primary:~# ping 10.0.0.3
PING 10.0.0.3 (10.0.0.3) 56(84) bytes of data.
64 bytes from 10.0.0.3: icmp_seq=1 ttl=64 time=0.298 ms
64 bytes from 10.0.0.3: icmp_seq=2 ttl=64 time=0.099 ms

深入 Bridge 其他議題

在整理這篇也有看很多東西,但是花很多時間在這邊實作演示。原本主要是讓我的 KVM Bridge

ARP 運作

Linux 虛擬網絡設備之 bridge - 閱坊裡面有提到 ping,裡面 arp 相關東西,這邊找了相關東西

br0 為什麼可以設定 IP

bridge必須要組態IP嗎?

在我們常見的物理交換機中,有可以配置IP和不能配置IP兩種,不能配置IP的交換機一般通過com口連上去做配置(更簡單的交換機連com口的沒有,不支持任何配置),而能配置IP的交換機可以在配置好IP之後,通過該IP遠程連接上去做配置,從而更方便。

bridge就屬於後一種交換機,自帶虛擬網卡,可以配置IP,該虛擬網卡一端連在bridge上,另一端跟協議棧相連。和物理交換機一樣,bridge的工作不依賴於該虛擬網卡,但bridge工作不代表機器能連上網,要看組網方式。

參考: Linux虚拟网络设备之bridge(桥) - Linux程序员 - SegmentFault 思否

推薦看裡面文章,其實後面很想針對一些 Case 做實作,但花的時間超出預期,所以就特別放在這邊。

我之前聽朋友說到網路孔不能設定 IP,那就是 L2 設備,但從不能配置IP的交換機一般通過com口連上去做配置(更簡單的交換機連com口的沒有,不支持任何配置)這段話感覺還是能做到的。但這邊不確定是不是真的這樣,我也沒辦法實驗。

Info
我原本 Google 搜尋 Linux Bridge 找到 Linux 虛擬網絡設備之 bridge - 閱坊備份圖
,但後來發現這個好像是轉貼的。下面有原本連結,內容介紹更多。

筆記型電腦的 WiFi 無法進行橋接

Linux kernel 不允許無線網路以 managed mode 進行橋接。但我們等下就會設定 hostapd 讓無線網路進入 master mode,因此這個錯誤暫時無視即可。

Info
Bing AI:
您可以使用以下命令來查看網路卡的模式: iwconfig

To add a wireless interface to a bridge, you first have to assign the wireless interface to an access point or start an access point with hostapd. Otherwise the wireless interface will not be added to the bridge.

Network bridge - ArchWiki

這裡的 WiFi 使用熱點模式並不符合我們的需求。因此,我最後選擇改用網路孔進行橋接。

相關連結

Linux network namespace, veth, birdge与路由-赵化冰的博客 | Zhaohuabing Blog

彩蛋