Contents

網路新手虛擬網路設備 veth pair 實作筆記

原本自己電腦 KVM 都特別要設定路由表特別把 IP 指定到 KVM 主機上面, KVM 主機也要設定 SNAT 設定上面,最近看到可以用橋接接受到外面設定 IP,這邊就簡單做個研究。看到 veth peer就好其實做看看。

Warning
本人非專業網路人員,針對網路蒐集一些資訊整理,實作把相關內容筆記下來,內容可能有誤。

網路文章

其實以前有就有看類似這種文章,但是就是有看沒有懂,難得這次看就比較有感覺,打鐵趁熱,就來實作看看。

上面會挑幾個簡單來實例。

前言

先了解名詞。

1
2
3
4
5
6
7
什麼是namespace

它是Linux內核的一項功能,能夠對內核資源進行分區,以使一組process看到指定一組資源,而另一組process看到另一組資源,所以namespace是linux用來進行資源的虛擬隔離方法

什麼是veth(virtual Ethernet)

是Linux 內核支援的一種虛擬網絡設備,是虛擬的網路裝置,veth 的兩端可以採用不同的網路namespace,所以可以用來做主機和容器之間的網路通信。

名詞解釋來源:[Linux] 內核虛擬Bridge, veth原理與實作 | Hands on Linux Kernel: bridge, veth | 黃大仙的雲端修行室

namespacecgroup那時候在學 docker 知道主要都是靠 Linux 核心模擬出來,我們知道 docker 建立出來網路和系統是隔離的,本篇 ip netns 可以對 network namespace 做一些操作,本篇會新增 network namespace網路做個簡單互通。

veth pair 顧名思義,veth-pair 就是一對的虛擬裝置介面,和 tap/tun 裝置不同的是,它都是成對出現的。一端連著協議棧,一端彼此相連著。如下圖所示:

https://user-images.githubusercontent.com/6058558/256970551-ca573f47-42bc-4bd8-9952-94ad5909ddcc.png
參考: Linux 虛擬網路裝置 veth-pair 詳解,看這一篇就夠了 - bakari - 部落格園

簡單來說,之前我一直在思考 GNS3設備跟設備之間都會拉一條線,不知道是怎麼模擬的。veth pair 簡單就是那一條線,在控制 veth 可以放置 namespace 裡面,當作把孔放置到設備上面。

Info

這邊可能不知道 Netowrk Protocaol Stack是什麼?我這邊簡單爬了一下就是 OSI 七層跟電腦供通,例如我們打 ping指令電腦是下面跑的,參考如下。

https://user-images.githubusercontent.com/6058558/256970706-7b6cba3f-b15f-4ec5-ba4e-d4d68f01141a.png

可參考:

簡單實作

因為電腦可能有裝 docker 或其他 VM。你的 interface 這邊可能會有很多種。你可以安裝multipass 工具。這是一個 multipass 快速建立 Ubuntu VM工具。這邊multipass有特別設定 kvm ,但理論上應該都差不多。

1
2
multipass start
multipass shell 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
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
2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:70:a6:04 brd ff:ff:ff:ff:ff:ff
    altname enp0s3
    inet 192.168.122.100/24 metric 100 brd 192.168.122.255 scope global dynamic ens3
       valid_lft 3552sec preferred_lft 3552sec
    inet6 fe80::5054:ff:fe70:a604/64 scope link
       valid_lft forever preferred_lft forever

介面卡很乾淨。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 先進去 root
sudo -i
# 建立兩個 network namespace
ip netns add ns0
ip netns add ns1
# 建立一對veth
ip link add veth0 type veth peer name veth1
# 將veth移動到netns中
ip link set veth0 netns ns0
ip link set veth1 netns ns1
# 設定 IP 和 啟動
ip netns exec ns0 ip addr add 172.18.0.2/24 dev veth0
ip netns exec ns0 ip link set veth0 up
ip netns exec ns1 ip addr add 172.18.0.3/24 dev veth1
ip netns exec ns1 ip link set veth1 up

之後使用 ns1 ping 172.18.0.2 是 ping 的到的。

1
2
3
4
5
root@primary:~# ip netns exec ns1 ping 172.18.0.2
PING 172.18.0.2 (172.18.0.2) 56(84) bytes of data.
64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.523 ms
64 bytes from 172.18.0.2: icmp_seq=2 ttl=64 time=0.085 ms
64 bytes from 172.18.0.2: icmp_seq=3 ttl=64 time=0.110 m

好了,其實 veth pair實作完成。就是這麼簡單,但是不熟網路或者第一次看到指令也不知道幹什麼事。這邊我整理一下。

指令解說

↓查詢有哪些 network namespace
ip netns [ list ]

↓新增一個 network namespace
ip netns add NETNSNAME

↓刪除 network namespace
ip [-all] netns del [ NETNSNAME ]

network namespace下指令。
ip [-all] netns exec [ NETNSNAME ] command…

上面用這個指令設定 namespace IP,可參考下方指令

1
ip netns exec ns0 ip addr add 172.18.0.2/24 dev veth0
Info
這邊很有趣,ip [-all] netns exec [ NETNSNAME ] command...,可以下ip netns exec ns0 bash進去 network namespace,注意這邊進去看起來是一個 vm,但也不要亂刪資料,雖然網路隔離,但資料跟實體是關聯的。我還以為那是一個虛擬空間。

ip address { add | change | replace } IFADDR dev IFNAME [
LIFETIME ] [ CONFFLAG-LIST ]
指令可以用縮寫ip addr,再回來看這個指令。

1
ip addr add 172.18.0.2/24 dev veth0
Info

常常看到ip addr 指令,但使用不常。有時不小心打錯 IP,這邊也有特別找一下調整 IP 方法。

ip addr replace/change 並不是針對網路卡進行更新的,而是將 網路卡+IP 同時作為判斷條件進行修改,即不能改 IP,但可以改其他參數。
如何要換 IP,則需要先刪除,再新增。
參考: * 【网络协议-7】IP 是怎么来的 | DemonLee’s Time

這個問AI也是得到類似答案,參考下文:

如果你在 Linux 上使用 ip addr add 命令錯誤地添加了一個 IP 地址,你可以使用以下步驟來進行調整:

  1. 確認你要調整的網絡介面的名稱,你可以使用 ip addr show 命令來查看已配置的 IP 地址和網絡介面。

  2. 使用 ip addr delete 命令刪除錯誤的 IP 地址。例如,假設你要刪除的錯誤 IP 地址是 192.168.0.100/24,網絡介面名稱是 eth0,則可以執行以下命令:

1
sudo ip addr delete 192.168.0.100/24 dev eth0

這將從 eth0 網絡介面中刪除指定的 IP 地址。

  1. 確認 IP 地址已成功刪除。你可以再次運行 ip addr show 命令來檢查網絡介面上的 IP 地址。

請注意,這些命令需要使用 root 或具有相應權限的使用者執行,你可能需要在命令前加上 sudo 來獲取足夠的權限。

此外,如果你希望將正確的 IP 地址添加到網絡介面,你可以使用 ip addr add 命令進行配置。例如:

1
sudo ip addr add 192.168.0.100/24 dev eth0

這會將 IP 地址 192.168.0.100/24 添加到 eth0 網絡介面上。請確保提供的 IP 地址和網絡介面名稱是正確的。

ip link add - add virtual link

看官方文章,這指令可以建立虛擬介面卡(veth)

ip link add <veth2 name> type veth peer name <veth2 name>

ip link set ….

看起來有很多東西可以設定,但其中把 device 放到 netns 裡面。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
       netns  { PID | NETNSNAME | NETNSFILE }
              move the device to the network namespace associated with
              process PID or the name NETNSNAME or the file NETNSFILE.

              Some devices are not allowed to change network namespace:
              loopback, bridge, wireless. These are network namespace
              local devices. In such case ip tool will return "Invalid
              argument" error. It is possible to find out if device is
              local to a single network namespace by checking netns-
              local flag in the output of the ethtool:

                      ethtool -k DEVICE

              To change network namespace for wireless devices the iw
              tool can be used. But it allows one to change network
              namespace only for physical devices and by process PID.

指令流程觀察介面

我們回顧這之前指令,新增指令順便觀察一下ip addr相關資訊。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 建立兩個 network namespace
ip netns add ns0
ip netns add ns1
# 建立一對veth
ip link add veth0 type veth peer name veth1
# 將veth移動到netns中
ip link set veth0 netns ns0
ip link set veth1 netns ns1
# 設定 IP 和 啟動
ip netns exec ns0 ip addr add 172.18.0.2/24 dev veth0
ip netns exec ns0 ip link set veth0 up
ip netns exec ns1 ip addr add 172.18.0.3/24 dev veth1
ip netns exec ns1 ip link set veth1 up
  1. 先看兩個 network namespace。
1
2
ip netns add ns0
ip netns add ns1

可以用 ip netns [list]查看那些 network namespace。

1
2
3
root@primary:~# ip netns
ns1 (id: 1)
ns0 (id: 0)
  1. 建立一對 veth-pair

ip link add veth0 type veth peer name veth1

https://user-images.githubusercontent.com/6058558/256982288-bb5c5bee-765d-4bc1-9f50-69a72244f5c6.png

這邊很有趣可以看到新增兩個veth0veth1。但這邊我們看到是veth1@veth0veth0@veth1

1
2
3
4
3: 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
4: 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
  1. 將 veth 移動到 netns 中
1
2
ip link set veth0 netns ns0
ip link set veth1 netns ns1

https://user-images.githubusercontent.com/6058558/256982634-3f2e73e0-f5d6-463f-b232-ee0c96892aae.png

我們外面 host 下面下ip addr找不到 veth。但 network namespace有看到移到 ns0ns1裡面去。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
root@primary:~# ip netns exec ns0 ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
4: veth0@if3: <BROADCAST,MULTICAST> 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 link-netns ns1
root@primary:~# ip netns exec ns1 ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3: veth1@if4: <BROADCAST,MULTICAST> 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 link-netns ns0
  1. 設定 IP 和 啟動 device。
1
2
3
4
ip netns exec ns0 ip addr add 172.18.0.2/24 dev veth0
ip netns exec ns0 ip link set veth0 up
ip netns exec ns1 ip addr add 172.18.0.3/24 dev veth1
ip netns exec ns1 ip link set veth1 up
Info

這邊能看到 interface 裡面veth0@if3@if3不需要打。這邊我有問 AI。

我那個 ip a指令看到 veth0@if4 後面@if4是什麼?為什麼我設定名字不需要打veth0@if4,要打veth0。

veth0@if4 中的 @if4 表示該接口是一個虛擬介面(Virtual Interface)的連接接口。

在這種情況下,veth0 是虛擬接口的名稱,而 @if4 表示該虛擬接口與物理介面 if4 相連接。虛擬接口通常是在 Linux 系統中使用的,用於連接不同的網絡命名空間(Network Namespace)或用於實現虛擬化網絡。

當你配置虛擬接口時,你只需要指定虛擬接口的名稱,不需要包含 @if4 的部分。例如,如果你想創建一個名為 veth0 的虛擬介面,可以使用以下命令:

1
ip link add veth0 type veth peer name veth1

這將在系統中創建一對連接的虛擬介面 veth0veth1。而 @if4 部分是系統自動生成的用於表示虛擬介面與其他介面(如 if4)的連接。

所以只需要使用 veth0 作為虛擬接口的名稱,而不需要包括 @if4 部分。其他類似的虛擬接口也遵循相同的模式,你只需要使用虛擬接口的名稱即可。

圖示解釋

因為我一開始也不是很熟指令,所以在看這些文章不太明白他們是在做什麼。這邊我整理指令對應圖片,應該也能讓菜鳥看懂在做什麼。應該吧XD

  1. 在我們還沒下指令,只有 host 主機。

https://user-images.githubusercontent.com/6058558/256983209-c2398418-b392-47f9-b23c-f52ee2998674.png

  1. 建立兩個 network namespace

2.1. ip netns add ns0
https://user-images.githubusercontent.com/6058558/256983269-c25beec2-6352-457a-af3f-03c0f1d7c47d.png

2.2. ip netns add ns1
https://user-images.githubusercontent.com/6058558/256983316-635faea4-1cbe-4e92-925b-f52a29286b9c.png

  1. 建立一對veth
    ip link add veth0 type veth peer name veth1

https://user-images.githubusercontent.com/6058558/256983467-4a136dfa-d53c-4838-8421-232f6bec7758.png

  1. 將veth移動到netns中

4.1. ip link set veth0 netns ns0

https://user-images.githubusercontent.com/6058558/256983511-380e4547-7612-4eed-bdcb-015065071b27.png

4.2. ip link set veth1 netns ns1

https://user-images.githubusercontent.com/6058558/256983534-9fb21d09-fe42-4d45-b139-5071efcde09b.png

後面設定 ip 就不需要特別畫了,透過指令跟圖片大概就知道這是幹嘛。這邊主機 Host 連不到兩個 network namespace ,這就是 linux 網路隔離,本機 host 看不到 namespace 網路介面卡。

host 連上 namespace(加碼)

我突然想 讓host 應該能連 ns0 上面,只需要加上 veth-pairns0去就可以了。這邊就動手實作。

1
2
3
4
5
6
ip link add veth2 type veth peer name veth3
ip link set veth2 netns ns0
ip netns exec ns0 ip addr add 172.19.0.2/24 dev veth2
ip netns exec ns0 ip link set veth2 up
ip addr add 172.19.0.4/24 dev veth3
ip link set veth3 up

還滿順利的。
https://user-images.githubusercontent.com/6058558/256985771-021b48a7-cb04-4e5c-8552-1d2397e0b2cf.png

總結

這個步驟做很多,我們學會透過 veth-pair 可以讓兩個namespace連線。但這樣我們新增一個 VM 不是很麻煩,都需要建立veth-pair,然後網域不能重複,這邊就需要bridge。當然ip addr學到一些資訊也不錯。

這樣我們新增一個 VM 不是很麻煩,都需要建立veth-pair

這邊我覺得很難解釋,但主要就是講Linux veth pair 详解 - 知乎這段內容。

https://user-images.githubusercontent.com/6058558/256986015-3ebf1eb1-3bc7-430a-ac99-0479228c1510.png

彩蛋

順便還被我挖到以前舊指令相對應新指令打法。查看 IP 指令和路由筆記/被廢棄掉的指令

https://user-images.githubusercontent.com/6058558/256969575-b719bef7-e879-4a63-823e-8c36150c439c.png