云原生虛擬網絡 tun/tap & veth-pair

云原生虛擬網絡 tun/tap & veth-pair

轉載請聲明出處哦~,本篇文章發布于luozhiyun的博客:https://www.luozhiyun.com/archives/684
以前在研究 k8s 網絡的時候,很多東西都看不太懂,只是蜻蜓點水過一下,這段時間打算惡補一下虛擬網絡方面的知識,感興趣的不妨一起探討學習一下 。
概述目前主流的虛擬網卡方案有tun/tap和veth兩種 。在時間上 tun/tap 出現得更早,在 Linux Kernel 2.4 版之后發布的內核都會默認編譯 tun/tap 的驅動 。并且tun/tap 應用非常廣泛 , 其中云原生虛擬網絡中,flannel 的 UDP 模式中的 flannel0 就是一個 tun 設備,OpenVPN 也利用到了 tun/tap 進行數據的轉發 。
veth 是另一種主流的虛擬網卡方案 , 在 Linux Kernel 2.6 版本 , Linux 開始支持網絡名空間隔離的同時,也提供了專門的虛擬以太網(Virtual Ethernet,習慣簡寫做 veth)讓兩個隔離的網絡名稱空間之間可以互相通信 。veth 實際上不是一個設備 , 而是一對設備,因而也常被稱作 Veth-Pair 。
Docker 中的 Bridge 模式就是依靠 veth-pair 連接到 docker0 網橋上與宿主機乃至外界的其他機器通信的 。
云原生虛擬網絡 tun/tap & veth-pair

文章插圖
tun/taptun 和 tap 是兩個相對獨立的虛擬網絡設備,它們作為虛擬網卡,除了不具備物理網卡的硬件功能外,它們和物理網卡的功能是一樣的,此外tun/tap負責在內核網絡協議棧和用戶空間之間傳輸數據 。
  • tun 設備是一個三層網絡層設備,從 /dev/net/tun 字符設備上讀取的是 IP 數據包,寫入的也只能是 IP 數據包,因此常用于一些點對點IP隧道,例如OpenVPN,IPSec等;
  • tap 設備是二層鏈路層設備,等同于一個以太網設備,從 /dev/tap0 字符設備上讀取 MAC 層數據??,写葰枘覀}荒蓯?MAC 層數據?。虼順S美醋魑檳饣D饌ㄊ褂茫?/li>

云原生虛擬網絡 tun/tap & veth-pair

文章插圖
從上面圖中,我們可以看出物理網卡和 tun/tap 設備模擬的虛擬網卡的區別,雖然它們的一端都是連著網絡協議棧,但是物理網卡另一端連接的是物理網絡,而 tun/tap 設備另一端連接的是一個文件作為傳輸通道 。
根據前面的介紹,我們大約知道虛擬網卡主要有兩個功能,一個是連接其它設備(虛擬網卡或物理網卡)和 Bridge 這是 tap 設備的作用;另一個是提供用戶空間程序去收發虛擬網卡上的數據,這是 tun 設備的作用 。
主要區別是因為它們作用在不同的網絡協議層,換句話說 tap設備是一個二層設備所以通常接入到 Bridge上作為局域網的一個節點,tun設備是一個三層設備通常用來實現 vpn 。
OpenVPN 使用 tun 設備收發數據OpenVPN 是使用 tun 設備的常見例子,它可以方便的在不同網絡訪問場所之間搭建類似于局域網的專用網絡通道 。其核心機制就是在 OpenVPN 服務器和客戶端所在的計算機上都安裝一個 tun 設備,通過其虛擬 IP 實現相互訪問 。
例如公網上的兩個主機節點A、B , 物理網卡上配置的IP分別是 ipA_eth0 和 ipB_eth0 。然后在A、B兩個節點上分別運行 openvpn 的客戶端和服務端 , 它們會在自己的節點上創建 tun 設備 , 且都會讀取或寫入這個 tun 設備 。
假設這兩個設備對應的虛擬 IP 是 ipA_tun0 和 ipB_tun0,那么節點 B 上面的應用程序想要通過虛擬 IP 對節點 A 通信,那么數據包流向就是:
云原生虛擬網絡 tun/tap & veth-pair

文章插圖
用戶進程對 ipA_tun0 發起請求,經過路由決策后內核將數據從網絡協議棧寫入 tun0 設備;然后 OpenVPN 從字符設備文件中讀取 tun0 設備數據,將數據請求發出去;內核網絡協議棧根據路由決策將數據從本機的 eth0 接口流出發往 ipA_eth0。
同樣我們來看看節點 A 是如何接受數據:
云原生虛擬網絡 tun/tap & veth-pair

文章插圖
當節點A 通過物理網卡 eth0 接受到數據后會將寫入內核網絡協議棧,因為目標端口號是OpenVPN程序所監聽的,所以網絡協議棧會將數據交給 OpenVPN ;
OpenVPN 程序得到數據之后,發現目標IP是tun0設備的,于是將數據從用戶空間寫入到字符設備文件中,然后 tun0 設備會將數據寫入到協議棧中,網絡協議棧最終將數據轉發給應用進程 。
從上面我們知道使用 tun/tap 設備傳輸數據需要經過兩次協議棧,不可避免地會有一定的性能損耗,如果條件允許,容器對容器的直接通信并不會把 tun/tap 作為首選方案 , 一般是基于稍后介紹的 veth 來實現的 。但是 tun/tap 沒有 veth 那樣要求設備成對出現、數據要原樣傳輸的限制 , 數據包到用戶態程序后,程序員就有完全掌控的權力,要進行哪些修改,要發送到什么地方,都可以編寫代碼去實現,因此 tun/tap 方案比起 veth 方案有更廣泛的適用范圍 。

推薦閱讀