獨立博客地址:https://ryan4yin.space/posts/linux-virtual-network-interfaces/

本文用到的字符畫工具:vscode-asciiflow2

Linux 具有强大的虛擬網絡能力,這也是 openstack 網絡、docker 容器網絡以及 kubernetes 網絡等虛擬網絡的基礎。

這裏介紹 Linux 常用的虛擬網絡接口類型:TUN/TAP、bridge 以及 veth。

一、tun/tap 虛擬網絡接口

tun/tap 是操作系統內核中的虛擬網絡設備,他們為用戶層程序提供數據的接收與傳輸。

普通的物理網絡接口如 eth0,它的兩端分別是內核協議棧和外面的物理網絡。

而對於 TUN/TAP 虛擬接口如 tun0,它的一端一定是連接的用戶層程序,另一端則視配置方式的不同而變化,可以直連內核協議棧,也可以是某個 bridge(後面會介紹)。

Linux 通過內核模塊 TUN 提供 tun/tap 功能,該模塊提供了一個設備接口 /dev/net/tun 供用戶層程序讀寫,用戶層程序通過 /dev/net/tun 讀寫主機內核協議棧的數據。

> modinfo tun
filename: /lib/modules/5.13.6-1-default/kernel/drivers/net/tun.ko.xz
alias: devname:net/tun
alias: char-major-10-200
license: GPL
author: (C) 1999-2004 Max Krasnyansky <[email protected]>
description: Universal TUN/TAP device driver
... > ls /dev/net/tun
/dev/net/tun

一個 TUN 設備的示例圖如下:


+----------------------------------------------------------------------+
| |
| +--------------------+ +--------------------+ |
| | User Application A | | User Application B +<-----+ |
| +------------+-------+ +-------+------------+ | |
| | 1 | 5 | |
|...............+......................+...................|...........|
| ↓ ↓ | |
| +----------+ +----------+ | |
| | socket A | | socket B | | |
| +-------+--+ +--+-------+ | |
| | 2 | 6 | |
|.................+.................+......................|...........|
| ↓ ↓ | |
| +------------------------+ +--------+-------+ |
| | Network Protocol Stack | | /dev/net/tun | |
| +--+-------------------+-+ +--------+-------+ |
| | 7 | 3 ^ |
|................+...................+.....................|...........|
| ↓ ↓ | |
| +----------------+ +----------------+ 4 | |
| | eth0 | | tun0 | | |
| +-------+--------+ +-----+----------+ | |
| 10.32.0.11 | | 192.168.3.11 | |
| | 8 +---------------------+ |
| | |
+----------------+-----------------------------------------------------+

Physical Network

因為 TUN/TAP 設備的一端是內核協議棧,顯然流入 tun0 的數據包是先經過本地的路由規則匹配的。

路由匹配成功,數據包被發送到 tun0 後,tun0 發現另一端是通過 /dev/net/tun 連接到應用程序 B,就會將數據丟給應用程序 B。

應用程序對數據包進行處理後,可能會構造新的數據包,通過物理網卡發送出去。比如常見的 VPN 程序就是把原來的數據包封裝/加密一遍,再發送給 VPN 服務器。

C 語言編程測試 TUN 設備

為了使用 tun/tap 設備,用戶層程序需要通過系統調用打開 /dev/net/tun 獲得一個讀寫該設備的文件描述符(FD),並且調用 ioctl() 向內核注册一個 TUN 或 TAP 類型的虛擬網卡(實例化一個 tun/tap 設備),其名稱可能是 tun0/tap0 等。

此後,用戶程序可以通過該 TUN/TAP 虛擬網卡與主機內核協議棧(或者其他網絡設備)交互。當用戶層程序關閉後,其注册的 TUN/TAP 虛擬網卡以及自動生成的路由錶相關條目都會被內核釋放。

可以把用戶層程序看做是網絡上另一臺主機,他們通過 tun/tap 虛擬網卡相連。

一個簡單的 C 程序示例如下,它每次收到數據後,都只單純地打印一下收到的字節數:

#include <linux/if.h>
#include <linux/if_tun.h> #include <sys/ioctl.h> #include <fcntl.h>
#include <string.h> #include <unistd.h>
#include<stdlib.h>
#include<stdio.h> int tun_alloc(int flags)
{ struct ifreq ifr;
int fd, err;
char *clonedev = "/dev/net/tun"; // 打開 tun 文件,獲得 fd
if ((fd = open(clonedev, O_RDWR)) < 0) {
return fd;
} memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = flags; // 向內核注册一個 TUN 網卡,並與前面拿到的 fd 關聯起來
// 程序關閉時,注册的 tun 網卡及自動生成的相關路由策略,會被自動釋放
if ((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0) {
close(fd);
return err;
} printf("Open tun/tap device: %s for reading...\n", ifr.ifr_name); return fd;
} int main()
{ int tun_fd, nread;
char buffer[1500]; /* Flags: IFF_TUN - TUN device (no Ethernet headers)
* IFF_TAP - TAP device
* IFF_NO_PI - Do not provide packet information
*/
tun_fd = tun_alloc(IFF_TUN | IFF_NO_PI); if (tun_fd < 0) {
perror("Allocating interface");
exit(1);
} while (1) {
nread = read(tun_fd, buffer, sizeof(buffer));
if (nread < 0) {
perror("Reading from interface");
close(tun_fd);
exit(1);
} printf("Read %d bytes from tun/tap device\n", nread);
}
return 0;
}

接下來開啟三個終端窗口來測試上述程序,分別運行上面的 tun 程序、tcpdump 和 iproute2 指令。

首先通過編譯運行上述 c 程序,程序會阻塞住,等待數據到達:

# 編譯,請忽略部分 warning
> gcc mytun.c -o mytun # 創建並監聽 tun 設備需要 root 權限
> sudo mytun
Open tun/tap device: tun0 for reading...

現在使用 iproute2 查看下鏈路層設備:

# 能發現最後面有列出名為 tun0 的接口,但是狀態為 down
* ip addr ls
......
3: wlp4s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether c0:3c:59:36:a4:16 brd ff:ff:ff:ff:ff:ff
inet 192.168.31.228/24 brd 192.168.31.255 scope global dynamic noprefixroute wlp4s0
valid_lft 41010sec preferred_lft 41010sec
inet6 fe80::4ab0:130f:423b:5d37/64 scope link noprefixroute
valid_lft forever preferred_lft forever
7: tun0: <POINTOPOINT,MULTICAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 500
link/none # 為 tun0 設置 ip 地址,注意不要和其他接口在同一網段,會導致路由沖突
> sudo ip addr add 172.21.22.23/24 dev tun0
# 啟動 tun0 這個接口,這一步會自動向路由錶中添加將 172.21.22.23/24 路由到 tun0 的策略
> sudo ip link set tun0 up
#確認上一步添加的路由策略是否存在
* ip route ls
default via 192.168.31.1 dev wlp4s0 proto dhcp metric 600
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
172.21.22.0/24 dev tun0 proto kernel scope link src 172.21.22.23
192.168.31.0/24 dev wlp4s0 proto kernel scope link src 192.168.31.228 metric 600 # 此時再查看接口,發現 tun0 狀態為 unknown
> ip addr ls
......
8: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 500
link/none
inet 172.21.22.23/24 scope global tun0
valid_lft forever preferred_lft forever
inet6 fe80::3d52:49b5:1cf3:38fd/64 scope link stable-privacy
valid_lft forever preferred_lft forever # 使用 tcpdump 嘗試抓下 tun0 的數據,會阻塞在這裏,等待數據到達
> tcpdump -i tun0

現在再啟動第三個窗口發點數據給 tun0,持續觀察前面 tcpdumpmytun 的日志:

# 直接 ping tun0 的地址,貌似有問題,數據沒進 mytun 程序,而且還有響應
* ping -c 4 172.21.22.23
PING 172.21.22.23 (172.21.22.23) 56(84) bytes of data.
64 bytes from 172.21.22.23: icmp_seq=1 ttl=64 time=0.167 ms
64 bytes from 172.21.22.23: icmp_seq=2 ttl=64 time=0.180 ms
64 bytes from 172.21.22.23: icmp_seq=3 ttl=64 time=0.126 ms
64 bytes from 172.21.22.23: icmp_seq=4 ttl=64 time=0.141 ms --- 172.21.22.23 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3060ms
rtt min/avg/max/mdev = 0.126/0.153/0.180/0.021 ms # 但是 ping 該網段下的其他地址,流量就會被轉發給 mytun 程序,因為 mytun 啥數據也沒回,自然丟包率 100%
# tcpdump 和 mytun 都會打印出相關日志
* ping -c 4 172.21.22.26
PING 172.21.22.26 (172.21.22.26) 56(84) bytes of data. --- 172.21.22.26 ping statistics ---
4 packets transmitted, 0 received, 100% packet loss, time 3055ms

下面給出 mytun 的輸出:

Read 84 bytes from tun/tap device
Read 84 bytes from tun/tap device
Read 84 bytes from tun/tap device
Read 84 bytes from tun/tap device

以及 tcpdump 的輸出:

00:22:03.622684 IP (tos 0x0, ttl 64, id 37341, offset 0, flags [DF], proto ICMP (1), length 84)
172.21.22.23 > 172.21.22.26: ICMP echo request, id 11, seq 1, length 64
00:22:04.633394 IP (tos 0x0, ttl 64, id 37522, offset 0, flags [DF], proto ICMP (1), length 84)
172.21.22.23 > 172.21.22.26: ICMP echo request, id 11, seq 2, length 64
00:22:05.653356 IP (tos 0x0, ttl 64, id 37637, offset 0, flags [DF], proto ICMP (1), length 84)
172.21.22.23 > 172.21.22.26: ICMP echo request, id 11, seq 3, length 64
00:22:06.677341 IP (tos 0x0, ttl 64, id 37667, offset 0, flags [DF], proto ICMP (1), length 84)
172.21.22.23 > 172.21.22.26: ICMP echo request, id 11, seq 4, length 64

更複雜的 tun 程序,可以參考

TUN 與 TAP 的區別

TUN 和 TAP 的區別在於工作的網絡層次不同,用戶程序通過 TUN 設備只能讀寫網絡層的 IP 數據包,而 TAP 設備則支持讀寫鏈路層的數據包(通常是以太網數據包,帶有 Ethernet headers)。

TUN 與 TAP 的關系,就類似於 socket 和 raw socket.

TUN/TAP 應用最多的場景是 VPN 代理,比如:

  1. clash: 一個支持各種規則的隧道,也支持 TUN 模式
  2. tun2socks: 一個全局透明代理,和 VPN 的工作模式一樣,它通過創建虛擬網卡+修改路由錶,在第三層網絡層代理系統流量。

二、veth

veth 接口總是成對出現,一對 veth 接口就類似一根網線,從一端進來的數據會從另一端出去。

同時 veth 又是一個虛擬網絡接口,因此它和 TUN/TAP 或者其他物理網絡接口一樣,也都能配置 mac/ip 地址(但是並不是一定得配 mac/ip 地址)。

其主要作用就是連接不同的網絡,比如在容器網絡中,用於將容器的 namespace 與 root namespace 的網橋 br0 相連。

容器網絡中,容器側的 veth 自身設置了 ip/mac 地址並被重命名為 eth0,作為容器的網絡接口使用,而主機側的 veth 則直接連接在 docker0/br0 上面。

使用 veth 的容器網絡的詳細示例圖,在下一節有提供。

三、bridge

Linux Bridge 是工作在鏈路層的網絡交換機,由 Linux 內核模塊 brige 提供,它負責在所有連接到它的接口之間轉發鏈路層數據包。

添加到 Bridge 上的設備被設置為只接受二層數據幀並且轉發所有收到的數據包到 Bridge 中。

在 Bridge 中會進行一個類似物理交換機的查MAC端口映射錶、轉發、更新MAC端口映射錶這樣的處理邏輯,從而數據包可以被轉發到另一個接口/丟弃/廣播/發往上層協議棧,由此 Bridge 實現了數據轉發的功能。

如果使用 tcpdump 在 Bridge 接口上抓包,可以抓到網橋上所有接口進出的包,因為這些數據包都要通過網橋進行轉發。

與物理交換機不同的是,Bridge 本身可以設置 IP 地址,可以認為當使用 brctl addbr br0 新建一個 br0 網橋時,系統自動創建了一個同名的隱藏 br0 網絡接口。br0 一旦設置 IP 地址,就意味著這個隱藏的 br0 接口可以作為路由接口設備,參與 IP 層的路由選擇(可以使用 route -n 查看最後一列 Iface)。因此只有當 br0 設置 IP 地址時,Bridge 才有可能將數據包發往上層協議棧。

但被添加到 Bridge 上的網卡是不能配置 IP 地址的,他們工作在數據鏈路層,對路由系統不可見。

它常被用於在虛擬機、主機上不同的 namepsaces 之間轉發數據。

虛擬機場景(橋接模式)

以 qemu-kvm 為例,在虛擬機的橋接模式下,qemu-kvm 會為每個虛擬機創建一個 tun/tap 虛擬網卡並連接到 br0 網橋。

虛擬機內部的網絡接口 eth0 是 qemu-kvm 軟件模擬的,實際上虛擬機內網絡數據的收發都會被 qemu-kvm 轉換成對 /dev/net/tun 的讀寫。

以發送數據為例,整個流程如下:

  • 虛擬機發出去的數據包先到達 qemu-kvm 程序
  • 數據被用戶層程序 qemu-kvm 寫入到 /dev/net/tun,到達 tap 設備
  • tap 設備把數據傳送到 br0 網橋
  • br0 把數據交給 eth0 發送出去

整個流程跑完,數據包都不需要經過宿主機的協議棧,效率高。

+------------------------------------------------+-----------------------------------+-----------------------------------+
| Host | VirtualMachine1 | VirtualMachine2 |
| | | |
| +--------------------------------------+ | +-------------------------+ | +-------------------------+ |
| | Network Protocol Stack | | | Network Protocol Stack | | | Network Protocol Stack | |
| +--------------------------------------+ | +-------------------------+ | +-------------------------+ |
| ↑ | ↑ | ↑ |
|.......................|........................|................|..................|.................|.................|
| ↓ | ↓ | ↓ |
| +--------+ | +-------+ | +-------+ |
| | .3.101 | | | .3.102| | | .3.103| |
| +------+ +--------+ +-------+ | +-------+ | +-------+ |
| | eth0 |<--->| br0 |<--->|tun/tap| | | eth0 | | | eth0 | |
| +------+ +--------+ +-------+ | +-------+ | +-------+ |
| ↑ ↑ ↑ +--------+ ↑ | ↑ |
| | | +------|qemu-kvm|-----------+ | | |
| | ↓ +--------+ | | |
| | +-------+ | | | |
| | |tun/tap| | | | |
| | +-------+ | | | |
| | ↑ | +--------+ | | |
| | +-------------------------------------|qemu-kvm|-------------|-----------------+ |
| | | +--------+ | |
| | | | |
+---------|--------------------------------------+-----------------------------------+-----------------------------------+

Physical Network (192.168.3.0/24)

跨 namespace 通信場景(容器網絡,NAT 模式)

由於容器運行在自己單獨的 network namespace 裏面,所以和虛擬機一樣,它們也都有自己單獨的協議棧。

容器網絡的結構和虛擬機差不多,但是它改用了 NAT 網絡,並把 tun/tap 換成了 veth,導致 docker0 過來的數據,要先經過宿主機協議棧,然後才進入 veth 接口。

多了一層 NAT,以及多走了一層宿主機協議棧,都會導致性能下降。

示意圖如下:

+-----------------------------------------------+-----------------------------------+-----------------------------------+
| Host | Container 1 | Container 2 |
| | | |
| +---------------------------------------+ | +-------------------------+ | +-------------------------+ |
| | Network Protocol Stack | | | Network Protocol Stack | | | Network Protocol Stack | |
| +----+-------------+--------------------+ | +-----------+-------------+ | +------------+------------+ |
| ^ ^ | ^ | ^ |
|........|.............|........................|................|..................|.................|.................|
| v v ↓ | v | v |
| +----+----+ +-----+------+ | +-----+-------+ | +-----+-------+ |
| | .31.101 | | 172.17.0.1 | +------+ | | 172.17.0.2 | | | 172.17.0.3 | |
| +---------+ +-------------<---->+ veth | | +-------------+ | +-------------+ |
| | eth0 | | docker0 | +--+---+ | | eth0(veth) | | | eth0(veth) | |
| +----+----+ +-----+------+ ^ | +-----+-------+ | +-----+-------+ |
| ^ ^ | | ^ | ^ |
| | | +------------------------+ | | |
| | v | | | |
| | +--+---+ | | | |
| | | veth | | | | |
| | +--+---+ | | | |
| | ^ | | | |
| | +------------------------------------------------------------------------------+ |
| | | | |
| | | | |
+-----------------------------------------------+-----------------------------------+-----------------------------------+
v
Physical Network (192.168.31.0/24)

每創建一個新容器,都會在容器的 namespace 裏新建一個 veth 接口並命令為 eth0,同時在主 namespace 創建一個 veth,將容器的 eth0 與 docker0 連接。

可以在容器中通過 iproute2 查看到, eth0 的接口類型為 veth

* docker run -it --rm debian:buster bash
[email protected]:/# ip --details addr ls
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 promiscuity 0 minmtu 0 maxmtu 0 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
20: [email protected]: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0 promiscuity 0 minmtu 68 maxmtu 65535
veth numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever

同時在宿主機中能看到對應的 veth 設備是綁定到了 docker0 網橋的:

* sudo brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242fce99ef5 no vethea4171a

四、其他虛擬網絡接口的類型

除了上面介紹的這些,Linux 還支持 VLAN、VXLAN 等類型的虛擬網絡接口,可通過 ip link help 查看,因為我接觸的少,這裏就不介紹了。

五、虛擬網絡接口的速率

Loopback 和本章講到的其他虛擬網絡接口一樣,都是一種軟件模擬的網絡設備。

他們的速率是不是也像物理鏈路一樣,存在鏈路層(比如以太網)的帶寬限制呢?

比如目前很多老舊的網絡設備,都是只支持到百兆以太網,這就决定了它的帶寬上限。

即使是較新的設備,目前基本也都只支持到千兆,也就是 1GbE 以太網標准,那本文提到的虛擬網絡接口單純在本機內部通信,是否也存在這樣的制約呢?是否也只能跑到 1GbE?

使用 ethtool 檢查:

# docker 容器的 veth 接口速率
> ethtool vethe899841 | grep Speed
Speed: 10000Mb/s # 網橋看起來沒有固定的速率
> ethtool docker0 | grep Speed
Speed: Unknown! # tun0 設備的默認速率貌似是 10Mb/s ?
> ethtool tun0 | grep Speed
Speed: 10Mb/s # 此外 ethtool 無法檢查 lo 以及 wifi 的速率

網絡性能實測

接下來實際測試一下,先給出機器參數:

* cat /etc/os-release
NAME="openSUSE Tumbleweed"
# VERSION="20210810"
... * uname -a
Linux legion-book 5.13.8-1-default #1 SMP Thu Aug 5 08:56:22 UTC 2021 (967c6a8) x86_64 x86_64 x86_64 GNU/Linux * lscpu
Architecture: x86_64
CPU(s): 16
Model name: AMD Ryzen 7 5800H with Radeon Graphics
... # 內存,單比特 MB
* free -m
total used free shared buff/cache available
Mem: 27929 4482 17324 249 6122 22797
Swap: 2048 0 2048

使用 iperf3 測試:

# 啟動服務端
iperf3 -s -------------
# 新窗口啟動客戶端,通過 loopback 接口訪問 iperf3-server,大概 49Gb/s
* iperf3 -c 127.0.0.1
Connecting to host 127.0.0.1, port 5201
[ 5] local 127.0.0.1 port 48656 connected to 127.0.0.1 port 5201
[ ID] Interval Transfer Bitrate Retr Cwnd
[ 5] 0.00-1.00 sec 4.46 GBytes 38.3 Gbits/sec 0 1.62 MBytes
[ 5] 1.00-2.00 sec 4.61 GBytes 39.6 Gbits/sec 0 1.62 MBytes
[ 5] 2.00-3.00 sec 5.69 GBytes 48.9 Gbits/sec 0 1.62 MBytes
[ 5] 3.00-4.00 sec 6.11 GBytes 52.5 Gbits/sec 0 1.62 MBytes
[ 5] 4.00-5.00 sec 6.04 GBytes 51.9 Gbits/sec 0 1.62 MBytes
[ 5] 5.00-6.00 sec 6.05 GBytes 52.0 Gbits/sec 0 1.62 MBytes
[ 5] 6.00-7.00 sec 6.01 GBytes 51.6 Gbits/sec 0 1.62 MBytes
[ 5] 7.00-8.00 sec 6.05 GBytes 52.0 Gbits/sec 0 1.62 MBytes
[ 5] 8.00-9.00 sec 6.34 GBytes 54.5 Gbits/sec 0 1.62 MBytes
[ 5] 9.00-10.00 sec 5.91 GBytes 50.8 Gbits/sec 0 1.62 MBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.00 sec 57.3 GBytes 49.2 Gbits/sec 0 sender
[ 5] 0.00-10.00 sec 57.3 GBytes 49.2 Gbits/sec receiver # 客戶端通過 wlp4s0 wifi 網卡(192.168.31.228)訪問 iperf3-server,實際還是走的本機,但是速度要比 loopback 快一點,可能是默認設置的問題
* iperf3 -c 192.168.31.228
Connecting to host 192.168.31.228, port 5201
[ 5] local 192.168.31.228 port 43430 connected to 192.168.31.228 port 5201
[ ID] Interval Transfer Bitrate Retr Cwnd
[ 5] 0.00-1.00 sec 5.12 GBytes 43.9 Gbits/sec 0 1.25 MBytes
[ 5] 1.00-2.00 sec 5.29 GBytes 45.5 Gbits/sec 0 1.25 MBytes
[ 5] 2.00-3.00 sec 5.92 GBytes 50.9 Gbits/sec 0 1.25 MBytes
[ 5] 3.00-4.00 sec 6.00 GBytes 51.5 Gbits/sec 0 1.25 MBytes
[ 5] 4.00-5.00 sec 5.98 GBytes 51.4 Gbits/sec 0 1.25 MBytes
[ 5] 5.00-6.00 sec 6.05 GBytes 52.0 Gbits/sec 0 1.25 MBytes
[ 5] 6.00-7.00 sec 6.16 GBytes 52.9 Gbits/sec 0 1.25 MBytes
[ 5] 7.00-8.00 sec 6.08 GBytes 52.2 Gbits/sec 0 1.25 MBytes
[ 5] 8.00-9.00 sec 6.00 GBytes 51.6 Gbits/sec 0 1.25 MBytes
[ 5] 9.00-10.00 sec 6.01 GBytes 51.6 Gbits/sec 0 1.25 MBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.00 sec 58.6 GBytes 50.3 Gbits/sec 0 sender
[ 5] 0.00-10.00 sec 58.6 GBytes 50.3 Gbits/sec receiver # 從容器中訪問宿主機的 iperf3-server,速度幾乎沒區別
* docker run -it --rm --name=iperf3-server networkstatic/iperf3 -c 192.168.31.228
Connecting to host 192.168.31.228, port 5201
[ 5] local 172.17.0.2 port 43436 connected to 192.168.31.228 port 5201
[ ID] Interval Transfer Bitrate Retr Cwnd
[ 5] 0.00-1.00 sec 4.49 GBytes 38.5 Gbits/sec 0 403 KBytes
[ 5] 1.00-2.00 sec 5.31 GBytes 45.6 Gbits/sec 0 544 KBytes
[ 5] 2.00-3.00 sec 6.14 GBytes 52.8 Gbits/sec 0 544 KBytes
[ 5] 3.00-4.00 sec 5.85 GBytes 50.3 Gbits/sec 0 544 KBytes
[ 5] 4.00-5.00 sec 6.14 GBytes 52.7 Gbits/sec 0 544 KBytes
[ 5] 5.00-6.00 sec 5.99 GBytes 51.5 Gbits/sec 0 544 KBytes
[ 5] 6.00-7.00 sec 5.86 GBytes 50.4 Gbits/sec 0 544 KBytes
[ 5] 7.00-8.00 sec 6.05 GBytes 52.0 Gbits/sec 0 544 KBytes
[ 5] 8.00-9.00 sec 5.99 GBytes 51.5 Gbits/sec 0 544 KBytes
[ 5] 9.00-10.00 sec 6.12 GBytes 52.5 Gbits/sec 0 544 KBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.00 sec 58.0 GBytes 49.8 Gbits/sec 0 sender
[ 5] 0.00-10.00 sec 58.0 GBytes 49.8 Gbits/sec receiver

把 iperf3-server 跑在容器裏再測一遍:

# 在容器中啟動 iperf3-server,並映射到宿主機端口 6201
> docker run -it --rm --name=iperf3-server -p 6201:5201 networkstatic/iperf3 -s
> docker inspect --format "{{ .NetworkSettings.IPAddress }}" iperf3-server
172.17.0.2
-----------------------------
# 測試容器之間互訪的速度,ip 為 iperf3-server 的容器 ip,速度要慢一些。
# 畢竟過了 veth -> veth -> docker0 -> veth -> veth 五層虛擬網絡接口
* docker run -it --rm networkstatic/iperf3 -c 172.17.0.2
Connecting to host 172.17.0.2, port 5201
[ 5] local 172.17.0.3 port 40776 connected to 172.17.0.2 port 5201
[ ID] Interval Transfer Bitrate Retr Cwnd
[ 5] 0.00-1.00 sec 4.74 GBytes 40.7 Gbits/sec 0 600 KBytes
[ 5] 1.00-2.00 sec 4.48 GBytes 38.5 Gbits/sec 0 600 KBytes
[ 5] 2.00-3.00 sec 5.38 GBytes 46.2 Gbits/sec 0 600 KBytes
[ 5] 3.00-4.00 sec 5.39 GBytes 46.3 Gbits/sec 0 600 KBytes
[ 5] 4.00-5.00 sec 5.42 GBytes 46.6 Gbits/sec 0 600 KBytes
[ 5] 5.00-6.00 sec 5.39 GBytes 46.3 Gbits/sec 0 600 KBytes
[ 5] 6.00-7.00 sec 5.38 GBytes 46.2 Gbits/sec 0 635 KBytes
[ 5] 7.00-8.00 sec 5.37 GBytes 46.1 Gbits/sec 0 667 KBytes
[ 5] 8.00-9.00 sec 6.01 GBytes 51.7 Gbits/sec 0 735 KBytes
[ 5] 9.00-10.00 sec 5.74 GBytes 49.3 Gbits/sec 0 735 KBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.00 sec 53.3 GBytes 45.8 Gbits/sec 0 sender
[ 5] 0.00-10.00 sec 53.3 GBytes 45.8 Gbits/sec receiver # 本機直接訪問容器 ip,走的是 docker0 網橋,居然還挺快
* iperf3 -c 172.17.0.2
Connecting to host 172.17.0.2, port 5201
[ 5] local 172.17.0.1 port 56486 connected to 172.17.0.2 port 5201
[ ID] Interval Transfer Bitrate Retr Cwnd
[ 5] 0.00-1.00 sec 5.01 GBytes 43.0 Gbits/sec 0 632 KBytes
[ 5] 1.00-2.00 sec 5.19 GBytes 44.6 Gbits/sec 0 703 KBytes
[ 5] 2.00-3.00 sec 6.46 GBytes 55.5 Gbits/sec 0 789 KBytes
[ 5] 3.00-4.00 sec 6.80 GBytes 58.4 Gbits/sec 0 789 KBytes
[ 5] 4.00-5.00 sec 6.82 GBytes 58.6 Gbits/sec 0 913 KBytes
[ 5] 5.00-6.00 sec 6.79 GBytes 58.3 Gbits/sec 0 1007 KBytes
[ 5] 6.00-7.00 sec 6.63 GBytes 56.9 Gbits/sec 0 1.04 MBytes
[ 5] 7.00-8.00 sec 6.75 GBytes 58.0 Gbits/sec 0 1.04 MBytes
[ 5] 8.00-9.00 sec 6.19 GBytes 53.2 Gbits/sec 0 1.04 MBytes
[ 5] 9.00-10.00 sec 6.55 GBytes 56.3 Gbits/sec 0 1.04 MBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.00 sec 63.2 GBytes 54.3 Gbits/sec 0 sender
[ 5] 0.00-10.00 sec 63.2 GBytes 54.3 Gbits/sec receiver # 如果走本機 loopback 地址 + 容器端口映射,速度就慢了好多
# 或許是因為用 iptables 做端口映射導致的?
* iperf3 -c 127.0.0.1 -p 6201
Connecting to host 127.0.0.1, port 6201
[ 5] local 127.0.0.1 port 48862 connected to 127.0.0.1 port 6201
[ ID] Interval Transfer Bitrate Retr Cwnd
[ 5] 0.00-1.00 sec 2.71 GBytes 23.3 Gbits/sec 0 1.37 MBytes
[ 5] 1.00-2.00 sec 3.64 GBytes 31.3 Gbits/sec 0 1.37 MBytes
[ 5] 2.00-3.00 sec 4.08 GBytes 35.0 Gbits/sec 0 1.37 MBytes
[ 5] 3.00-4.00 sec 3.49 GBytes 30.0 Gbits/sec 0 1.37 MBytes
[ 5] 4.00-5.00 sec 5.50 GBytes 47.2 Gbits/sec 2 1.37 MBytes
[ 5] 5.00-6.00 sec 4.06 GBytes 34.9 Gbits/sec 0 1.37 MBytes
[ 5] 6.00-7.00 sec 4.12 GBytes 35.4 Gbits/sec 0 1.37 MBytes
[ 5] 7.00-8.00 sec 3.99 GBytes 34.3 Gbits/sec 0 1.37 MBytes
[ 5] 8.00-9.00 sec 3.49 GBytes 30.0 Gbits/sec 0 1.37 MBytes
[ 5] 9.00-10.00 sec 5.51 GBytes 47.3 Gbits/sec 0 1.37 MBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.00 sec 40.6 GBytes 34.9 Gbits/sec 2 sender
[ 5] 0.00-10.00 sec 40.6 GBytes 34.9 Gbits/sec receiver # 可走 wlp4s0 + 容器端口映射,速度也不慢啊
* iperf3 -c 192.168.31.228 -p 6201
Connecting to host 192.168.31.228, port 6201
[ 5] local 192.168.31.228 port 54582 connected to 192.168.31.228 port 6201
[ ID] Interval Transfer Bitrate Retr Cwnd
[ 5] 0.00-1.00 sec 4.34 GBytes 37.3 Gbits/sec 0 795 KBytes
[ 5] 1.00-2.00 sec 4.78 GBytes 41.0 Gbits/sec 0 834 KBytes
[ 5] 2.00-3.00 sec 6.26 GBytes 53.7 Gbits/sec 0 834 KBytes
[ 5] 3.00-4.00 sec 6.30 GBytes 54.1 Gbits/sec 0 875 KBytes
[ 5] 4.00-5.00 sec 6.26 GBytes 53.8 Gbits/sec 0 875 KBytes
[ 5] 5.00-6.00 sec 5.75 GBytes 49.4 Gbits/sec 0 875 KBytes
[ 5] 6.00-7.00 sec 5.49 GBytes 47.2 Gbits/sec 0 966 KBytes
[ 5] 7.00-8.00 sec 5.72 GBytes 49.1 Gbits/sec 2 966 KBytes
[ 5] 8.00-9.00 sec 4.81 GBytes 41.3 Gbits/sec 2 966 KBytes
[ 5] 9.00-10.00 sec 5.98 GBytes 51.4 Gbits/sec 0 966 KBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.00 sec 55.7 GBytes 47.8 Gbits/sec 4 sender
[ 5] 0.00-10.00 sec 55.7 GBytes 47.8 Gbits/sec receiver

總的來看,loopback、bridge、veth 這幾個接口基本上是沒被限速的,veth 有查到上限為 10000Mb/s(10Gb/s) 感覺也是個假數字,

實際上測出來的數據基本在 35Gb/s 到 55Gb/s 之間,視情况浮動。

性能的變化和虛擬網絡設備的鏈路和類型有關,或許和默認配置的區別也有關系。

另外 TUN 設備這裏沒有測,ethtool tun0 查到的值是比較離譜的 10Mb/s,但是感覺不太可能這麼慢,有時間可以再測一波看看。

參考

Linux 中的虛擬網絡接口的更多相關文章

  1. kvm虛擬機中virbr0虛擬網絡接口的删除與恢複

    安裝 KVM 後都會發現網絡接口裏多了一個叫做 virbr0 的虛擬網絡接口 一般情况下,虛擬網絡接口virbr0用作nat,以允許虛擬機訪問網絡服務,但nat一般不用於生產環境.我們可以使用以下方法 ...

  2. LINUX中的虛擬文件系統結構

    我的博客:www.while0.com 以下以2.6.32版本的內核源碼為例: 虛擬文件系統與具體文件系統之間是幾組操作函數的對應,包括file_operations,dentry_operation ...

  3. Linux中Postfix虛擬用戶及虛擬域(六)

    Postfix基於虛擬用戶虛擬域的郵件架構 上圖是一個幾乎完整的郵件系統架構圖,這裏基於Mysql數據庫進行用戶認證,不管是Postfix.Dovecot.webmail都需要去Mysql數據庫中進行 ...

  4. linux中設置虛擬域名

    一.打開tomcat安裝目錄下conf/server.xml這個文件在server.xml文檔中找到 </Engine></Service> 接著添加上面添加以下內容(暫時先說 ...

  5. 如何在 Linux 中查看可用的網絡接口

    在我們安裝完一個 Linux 系統後最為常見的任務便是網絡配置了.當然,你可以在安裝系統時進行網絡接口的配置.但是,對於某些人來說,他們更偏愛在安裝完系統後再進行網絡的配置或者更改現存的設置.眾所周知 ...

  6. 【轉】如何在 Linux 中查看可用的網絡接口

    原文:https://www.cnblogs.com/qianpangzi/p/10563979.html 查看ubuntu系統當前的可用的網絡接口.方法如下 -------------------- ...

  7. Linux 中查看可用的網絡接口

    目錄 Linux 中查看可用的網絡接口 在 Linux 中找到可用的網絡接口 title: Linux 中查看可用的網絡接口 date: 2020/2/25 16:56:36 toc: true -- ...

  8. linux網絡配置相關命令、虛擬網絡接口eth0:0

    網絡接口(interface)是網絡硬件設備在操作系統中的錶示方法,比如網卡在Linux操作系統中用ethX,是由0開始的正整數,比如eth0.eth1...... ethX.而普通猫和ADSL的接口 ...

  9. [轉載]Linux中的網絡接口及LO回環接口

    轉自:https://blog.csdn.net/weixin_39863747/article/details/80564358 Linux中的網絡接口及LO回環接口 2018年06月04日 10: ...

  10. linux 中/proc 詳解

    proc 文件系統 在Linux中有額外的機制可以為內核和內核模塊將信息發送給進程-- /proc 文件系統.最初設計的目的是允許更方便的對進程信息進行訪問(因此得名),現在它被每一個有有趣的東西報告 ...

隨機推薦

  1. sublime text3 使用SVN插件

    Simon在項目中經常使用SVN,每次都要切換提交,很麻煩,有了這個SVN插件就很方便了,使用快捷方式提交,更新. 安裝: Ctrl + Shift + P 調用出Sublime Text的包管理工具 ...

  2. maven install 構建報錯

    錯誤:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin: 2.3 . 2 :compile ( default ...

  3. php時間戳之間相互轉換

    第一種情况: 將時間戳轉換成年月日格式 <?php echo date('Y-m-d H:i:s',$v['apply_time']);?> 第二種情况: 將年月日轉換成時間戳 strto ...

  4. 為自己搭建一個鵲橋 -- Native Page與Web View之間的JSBridge實現方式

    說起JSBridge,大家最熟悉的應該就是微信的WeixinJSBridge,通過它各個公眾頁面可以調用後臺方法和微信進行交互,為用戶提供相關功能.我們就來說說UWP下怎麼樣實現我們自己的JSBrid ...

  5. Spring學習(三)——Spring中的依賴注入的方式

    [前面的話] Spring對我太重要了,做個關於web相關的項目都要使用Spring,每次去看Spring相關的知識,總是感覺一知半解,沒有很好的系統去學習一下,現在抽點時間學習一下Spring.不知 ...

  6. 又是一個二模02,不過day2

    話說比較簡單.除了第三題不會寫平衡樹啊你妹!!邊做邊寫吧. 機智的鏈接~機智的鏈接~機智的鏈接~機智的鏈接~機智的鏈接~機智的鏈接~機智的鏈接~機智的鏈接~機智的鏈接~機智的鏈接~機智的鏈接~機智的鏈 ...

  7. python實現指定目錄下批量文件的單詞計數:串行版本

    直接上代碼. 練習目標: 1.  使用 Python 面向對象的方法封裝邏輯和錶達 : 2.  使用异常處理和日志API : 3.  使用文件目錄讀寫API : 4.  使用 list, map, t ...

  8. 開濤spring3(9.4) - Spring的事務 之 9.4 聲明式事務

    9.4  聲明式事務 9.4.1  聲明式事務概述 從上節編程式實現事務管理可以深刻體會到編程式事務的痛苦,即使通過代理配置方式也是不小的工作量. 本節將介紹聲明式事務支持,使用該方式後最大的獲益是簡 ...

  9. mysql(4)—— 錶連接查詢與where後使用子查詢的性能分析。

    子查詢就是在一條查詢語句中還有其它的查詢語句,主查詢得到的結果依賴於子查詢的結果. 子查詢的子語句可以在一條sql語句的FROM,JOIN,和WHERE後面,本文主要針對在WHERE後面使用子查詢與錶 ...

  10. openssl 生成證書

    nginx生成證書,一共四步 1) 生成RSA私鑰 (會要求輸入至少4比特密碼)# openssl genrsa -des3 -out private.key 2048 # 2) 根據已生成的RSA私鑰 ...