網絡虛擬化技術 -- LXC TUN/TAP MACVLAN MACVTAP


Linux的網絡虛擬化是LXC項目中的一個子項目,LXC包括文件系統虛擬化,進程空間虛擬化,用戶虛擬化,網絡虛擬化,等等 
LXC內核命名空間 ],這里使用LXC的網絡虛擬化來模擬多個網絡環境。

創建虛擬網絡環境

使用命令

$ ip netns add net0

可以創建一個完全隔離的新網絡環境,這個環境包括一個獨立的網卡空間,路由表,ARP表,ip地址表,iptables,ebtables,等等。總之,與網絡有關的組件都是獨立的。

ip命令需要root權限的,但是由於本文大量使用ip命令,於是筆者給ip命令添加了capability,使普通用戶也能使用ip命令

使用命令

$ ip netns list
net0

可以看到我們剛才創建的網絡環境

進入虛擬網絡環境

使用命令

$ ip netns exec net0 `command`

我們可以在 net0 虛擬環境中運行任何命令

$ ip netns exec net0 bash
$ ip ad
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

這樣我們可以在新的網絡環境中打開一個shell,可以看到,新的網絡環境里面只有一個lo設備,並且這個lo設備與外面的lo設備是不同的,之間不能互相通訊。

連接兩個網絡環境

新的網絡環境里面沒有任何網絡設備,並且也無法和外部通訊,就是一個孤島,通過下面介紹的這個方法可以把兩個網絡環境連起來,簡單的說,就是在兩個網絡環境之間拉一根網線

$ ip netns add net1

先創建另一個網絡環境net1,我們的目標是把net0與net1連起來

$ ip link add type veth
$ ip ad
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
81: veth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether 12:39:09:81:3a:dd brd ff:ff:ff:ff:ff:ff
82: veth1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether 32:4f:fd:cc:79:1b brd ff:ff:ff:ff:ff:ff

這里創建連一對veth虛擬網卡,類似pipe,發給veth0的數據包veth1那邊會收到,發給veth1的數據包veth0會收到。就相當於給機器安裝了兩個網卡,並且之間用網線連接起來了

$ ip link set veth0 netns net0
$ ip link set veth1 netns net1

這兩條命令的意思就是把veth0移動到net0環境里面,把veth1移動到net1環境里面,我們看看結果

$ ip ad
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
$ ip netns exec net0 ip ad
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
81: veth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether 12:39:09:81:3a:dd brd ff:ff:ff:ff:ff:ff
$ ip netns exec net1 ip ad
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
82: veth1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether 32:4f:fd:cc:79:1b brd ff:ff:ff:ff:ff:ff

veth0 veth1已經在我們的環境里面消失了,並且分別出現在net0與net1里面。下面我們簡單測試一下net0與net1的聯通性

$ ip netns exec net0 ip link set veth0 up
$ ip netns exec net0 ip address add 10.0.1.1/24 dev veth0
$ ip netns exec net1 ip link set veth1 up
$ ip netns exec net1 ip address add 10.0.1.2/24 dev veth1

分別配置好兩個設備,然后用ping測試一下聯通性:

$ ip netns exec net0 ping -c 3 10.0.1.2
PING 10.0.1.2 (10.0.1.2) 56(84) bytes of data.
64 bytes from 10.0.1.2: icmp_req=1 ttl=64 time=0.101 ms
64 bytes from 10.0.1.2: icmp_req=2 ttl=64 time=0.057 ms
64 bytes from 10.0.1.2: icmp_req=3 ttl=64 time=0.048 ms

--- 10.0.1.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.048/0.068/0.101/0.025 ms

一個稍微復雜的網絡環境

2013-02-29-linux-network-emulator__1.png

創建虛擬網絡環境並且連接網線

ip netns add net0
ip netns add net1
ip netns add bridge
ip link add type veth
ip link set dev veth0 name net0-bridge netns net0
ip link set dev veth1 name bridge-net0 netns bridge
ip link add type veth
ip link set dev veth0 name net1-bridge netns net1
ip link set dev veth1 name bridge-net1 netns bridge

在bridge中創建並且設置br設備

ip netns exec bridge brctl addbr br
ip netns exec bridge ip link set dev br up
ip netns exec bridge ip link set dev bridge-net0 up
ip netns exec bridge ip link set dev bridge-net1 up
ip netns exec bridge brctl addif br bridge-net0
ip netns exec bridge brctl addif br bridge-net1

然后配置兩個虛擬環境的網卡

ip netns exec net0 ip link set dev net0-bridge up
ip netns exec net0 ip address add 10.0.1.1/24 dev net0-bridge
ip netns exec net1 ip link set dev net1-bridge up
ip netns exec net1 ip address add 10.0.1.2/24 dev net1-bridge

測試

$ ip netns exec net0 ping -c 3 10.0.1.2
PING 10.0.1.2 (10.0.1.2) 56(84) bytes of data.
64 bytes from 10.0.1.2: icmp_req=1 ttl=64 time=0.121 ms
64 bytes from 10.0.1.2: icmp_req=2 ttl=64 time=0.072 ms
64 bytes from 10.0.1.2: icmp_req=3 ttl=64 time=0.069 ms

--- 10.0.1.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.069/0.087/0.121/0.025 ms

配置lldpd檢查線路鏈接情況

隨着虛擬網絡環境增加,環境中網卡數量也在不斷增加,經常會忘記環境中哪些網卡連接到哪里,通過 lldp 
Link Layer Discovery Protocol ]
協議,我們可以清楚看到每個網卡連接到了哪些環境中的哪個網卡。

github 上有一個 lldp 在 linux 下的開源實現 
implementation of IEEE 802.1ab (LLDP) ]
,通過在每個環境中起一個 lldp daemon,我們就可以實時查看每個網卡的連接情況

Bridge 上 lldp 的數據

$ lldpcli show neighbors

LLDP neighbors:

Interface:    bridge-net0, via: LLDP, RID: 2, Time: 0 day, 00:06:53
  Chassis:
    ChassisID:    mac 82:be:2a:ec:70:69
    SysName:      localhost
    SysDescr:     net0
    Capability:   Bridge, off
    Capability:   Router, off
    Capability:   Wlan, off
  Port:
    PortID:       mac 82:be:2a:ec:70:69
    PortDescr:    net0-bridge

Interface:    bridge-net1, via: LLDP, RID: 1, Time: 0 day, 00:06:53
  Chassis:
    ChassisID:    mac b2:34:28:b1:be:49
    SysName:      localhost
    SysDescr:     net1
    Capability:   Bridge, off
    Capability:   Router, off
    Capability:   Wlan, off
  Port:
    PortID:       mac b2:34:28:b1:be:49
    PortDescr:    net1-bridge
 

 

TUN 設備

TUN 設備是一種虛擬網絡設備,通過此設備,程序可以方便得模擬網絡行為。先來看看物理設備是如何工作的:

2013-03-27-linux-network-tun__1.png

所有物理網卡收到的包會交給內核的 Network Stack 處理,然后通過 Socket API 通知給用戶程序。下面看看 TUN 的工作方式:

2013-03-27-linux-network-tun__2.png

普通的網卡通過網線收發數據包,但是 TUN 設備通過一個文件收發數據包。所有對這個文件的寫操作會通過 TUN 設備轉換成一個數據包送給內核;當內核發送一個包給 TUN 設備時,通過讀這個文件可以拿到包的內容。

如果我們使用 TUN 設備搭建一個基於 UDP VPN,那么整個處理過程就是這樣:

2013-03-27-linux-network-tun__3.png

數據包會通過內核網絡棧兩次。但是經過 App 的處理后,數據包可能已經加密,並且原有的 ip 頭被封裝在 udp 內部,所以第二次通過網絡棧內核看到的是截然不同的網絡包。

TAP 設備

TAP 設備與 TUN 設備工作方式完全相同,區別在於:

  • TUN 設備的 /dev/tunX 文件收發的是 IP 層數據包,只能工作在 IP 層,無法與物理網卡做 bridge,但是可以通過三層交換(如 ip_forward)與物理網卡連通。

  • TAP 設備的 /dev/tapX 文件收發的是 MAC 層數據包,擁有 MAC 層功能,可以與物理網卡做 bridge,支持 MAC 層廣播

MACVLAN

有時我們可能需要一塊物理網卡綁定多個 IP 以及多個 MAC 地址,雖然綁定多個 IP 很容易,但是這些 IP 會共享物理網卡的 MAC 地址,可能無法滿足我們的設計需求,所以有了 MACVLAN 設備,其工作方式如下:

2013-03-27-linux-network-tun__4.png

MACVLAN 會根據收到包的目的 MAC 地址判斷這個包需要交給哪個虛擬網卡。單獨使用 MACVLAN 好像毫無意義,但是配合之前介紹的 network namespace 使用,我們可以構建這樣的網絡:

2013-03-27-linux-network-tun__5.png

由於 macvlan 與 eth0 處於不同的 namespace,擁有不同的 network stack,這樣使用可以不需要建立 bridge 在 virtual namespace 里面使用網絡。

MACVTAP

MACVTAP 是對 MACVLAN的改進,把 MACVLAN 與 TAP 設備的特點綜合一下,使用 MACVLAN 的方式收發數據包,但是收到的包不交給 network stack 處理,而是生成一個 /dev/tapX 文件,交給這個文件:

2013-03-27-linux-network-tun__6.png

由於 MACVLAN 是工作在 MAC 層的,所以 MACVTAP 也只能工作在 MAC 層,不會有 MACVTUN 這樣的設備。

 

轉載:https://blog.kghost.info/2013/03/01/linux-network-emulator/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM