Contents

讓虛擬網路孔和各種設備連接起來 - Linux Bridge 實作

最近要讓 KVM 不透過設定路由,想直接連接到現有網段,這邊繼網路新手虛擬網路設備 veth pair 實作筆記 - 程式狂想筆記這篇研究,我們這邊簡單操作 Linux Bridge 讓多種孔可以互相連線。

參考這篇範例Linux Bridge 详解 | 没有理想的人不伤心在 Ubuntu 就可以實作出來,不過我發現bridge-utils大多數 Linux 都沒安裝。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 和 NAT 差異,這邊看完就應該知道 Bridge 原理和一些要注意的問題。

指令解說

安裝路由工具

這邊說明一下兩個工具安裝方法,這邊假如你要用新方法iproute2通常不需要再額外安裝。

  • iproute2
1
sudo apt-get install -y iproute2

舊方法。

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

新增網橋

bridge-utils 裡面提供 brctl去控制 bridge操作,這邊brctl方便去記,簡單來說就是bridge control。現在很多台電腦沒有這個指令,可以用新方法。

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

brctl 相關指令,通常加了加錯要想辦法還原,這邊特別紀錄一下,雖然重開機就會還原就是了。

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

新方法使用 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

新增兩對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

將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

簡單繪圖

https://user-images.githubusercontent.com/6058558/268509638-35b3c5fd-ccb4-4681-a606-df5971df5267.png

原本想說跟上篇一樣一個一個畫,不過後來覺得不需要。照著做也能可以了解。

加分題 host 連接到 br0

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

設定 br0

設定 br0 IP。

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 不能做 bridge

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

Tip
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.

這邊 wifi 用熱點模式就有非我想要的。所以後來我改網路孔去做 bridge。

相關連結