最近幾篇都是寫跟 QEMU 有關的,主要是發現 QEMU 在嵌入式系統開發上有很大的用處。有興趣的讀者可以回顧一下這兩篇,以 QEMU 加速嵌入式系統開發、利用 Raspberry Pi 4 硬體虛擬化加速開發ARM專案。
之前QEMU對網路的用法都是以 NAT 的方式配合 port forward 來使用,好處就是上網比較容易,也無需特別的設定,可以說很適合基本的使用。如果有需要連到 Guest 內,也可以透過設定 port forwarding 的設定,就可達成這個目的。
在較複雜的應用內,就會希望每個 Guest 可以有多張網卡可以跟 Host 做連接,透過橋接設定就可以做複雜的應用。本文主要的目的,就是要介紹怎麼設定 QEMU 來設定獨立網卡達成個種應用。
NAT 模式設定
NAT 模式是最常用的設定方式,也僅需要一般的使用者權限就可執行,並且可以達到大部份的需求。NAT 一般的設定看起來會像這樣
1 |
qemu-system-i386 {其它參數...} -nic user |
這樣就會有基本的 NAT 功能,eth0 透過 dhcp 可以取得 10.0.2.15 的 IP,Gateway 是 10.0.2.2,這樣就可以上網了。如果有需要從 Host 連到 Guest 內,就加上 port forwarding 的參數。
1 |
qemu-system-i386 {其它參數...} -nic user,hostfwd=tcp::8489-:80,hostfwd=udp::6759-:6789 |
從外部連到 Host 的 port 8489,就會連到 Guest 內的 port 80。UDP 也是類似的設定,連到 Host 的 6759 port,就可以轉到 Guest 的 6789 port。
橋接模式設定
這邊講的橋接模式,其實很彈性很大。依據不同的設定,使用者要設定成 Guest – Host only、NAT或者與實體網路橋接都可以。
橋接模式,主要是 Host 會產生 TAP Device 來供給 Guest 使用。使用者可以把 TAP Device 視做虛擬的網卡,當我們指定 Guest 使用指定的 TAP 裝置時,Guest 內的 eth device 就會跟 Host 的 TAP 互通。所以,在 Host 上將 TAP 加到 bridge 內時,同一個 bridge 內的裝置就可以互通。當用 iptables 來設置 masquerade,就可以達到 NAT 的功能。
自動產生 TAP 裝置
要產生 tap device,需要有 root 權限才行。所以,你如果有 root 權限就不用擔心太多,如果沒有的話也可以請管理員預先設置所需的 TAP 和 bridge device,在執行 QEMU 的時候就可以用一般權限執行。
有 root 權限的情況下,可以執行以下命令,就會自行產生 tap device,並和 HOST 的 Bridge 橋接。
1 |
qemu-system-i386 {其它參數...} -nic tap |
一般狀況下,單純的指定 tap 並無法利即使用,當產生 tap device 時,QEMU 會在開始時或執行腳本 /etc/qemu-ifup,結束時執行 /etc/qemu-ifdown。 qemu-ifup 腳本會判斷 HOST 是不是有 bridge 裝置,而且是不是在 default route 上,如果是的話,會自動將新產生的 tap device 加入該 bridge。這樣 Guest 開機時,就可以透過 eth0 上與實體網路連接,而透過 DHCP 或固定 IP 來連接網路。
手動產生 TAP 裝置
方案一 虛實相連
這是我比較建議的方式,比較能掌握網路的設定。這邊先做幾個使用情境的假設
- 管理員可以幫你預先產生 TAP 和 Bridge 的裝置
- 全部的網路,包含 tap 與實體網路,都橋接在 Bridge ‘br0’ 上
要做上面的設定,可以在 HOST 的 rc.local 內先進行設定,新的 Ubuntu 預設沒有 rc.local 了,可以先參考「Ubuntu 設定 rc.local」加入這功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#!/bin/sh brctl addbr br0 brctl addif br0 eth0 ifconfig eth0 0.0.0.0 ifconfig br0 192.168.1.100 ifconfig eth0 up route add default gw 192.168.1.254 for i in `seq 10 20` do ip tuntap add mode tap tap$i ifconfig tap$i up brctl addif br0 tap$i done |
上面的命令,就可以在HOST開機時預先產生 tap10 ~ tap20 的裝置,並加入 br0 當中,並與實體網路 eth0 橋接在一起。而在啟動 QEMU 時,透過以下命令指定介面。
1 |
qemu-system-i386 {其它參數...} -nic tap,ifname=tap10,mac=00:33:22:11:00:22,script=no,downscript=no |
這個命令就可指定使用 tap10裝置,並指定它的 MAC,不然進 Guest 後每台虛擬機都會有一樣的 MAC address 會發生通聯問題。script 和 downscript 因為需要root權限,都指定不要執行。如此,Guest 就可以和實體網路通聯,也可以直接連進 Guest 的服務,無需再用 port forwarding。
MAC address 如果不在此處指定,也可以進到 Guest 後,再以 ifconfig eth0 hw ether XX:XX:XX:XX:XX:XX 的方式指定,但 eth0 需要 down 的狀態下才行。
這個方式的設定各 Guest 可以互通,也可以跟外面的實體網路上的機器通聯。
方案二 虛實分開
如果你希望和實體網路隔開,可以在rc.local只將 tap X加入 br0 就好,Host 的 eth0 不要加入。這樣 Host 和 Guest 間可以通訊,Guest 間也可以通訊,但 Guest 和實體網路是無法通訊的。
方案三 虛擬網路 NAT 上網
在虛實分開的方案下,要讓虛擬網卡可以上網,就是透過 iptables 實行 NAT 就可以了。這邊假設設 Guest 裡的 IP 為 192.168.2.x,Host br0 IP 為 192.168.2.254。
1 2 |
echo 1 > /proc/sys/net/ipv4/ip_forward iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE |
方案四 個人虛實合一網路
如果只有單純的幾個人在實體網路需要存取Guest,那可以利用設定 Linux 與 Windows Routing 的方式來達成這個功能。先在Host上啟動 Routing 功能
1 |
echo 1 > /proc/sys/net/ipv4/ip_forward |
Window 上,則些加入虛擬網卡的 Next Route 訊息。這樣就只有知道 Guest 網域的人,才能和其互通了。
1 |
route add 192.168.2.0 mask 255.255.255.0 192.168.1.100 |
NAT+TAP 合用
QEMU 的 NAT 和 TAP 也可以合用,就是兩個參數一起下而已,甚至有多個TAP裝置。這樣就可以有私有網路,和一個快速連接到公網的網路
1 2 3 4 |
NATPARAM="-nic user,hostfwd=tcp::8489-:80,hostfwd=udp::6759-:6789" TAPPARAM1="-nic tap,ifname=tap10,mac=00:33:22:11:00:22,script=no,downscript=no" TAPPARAM2="-nic tap,ifname=tap10,mac=00:33:22:11:00:23,script=no,downscript=no" qemu-system-i386 {其它參數...} $NATPARAM $TAPPARAM1 $TAPPARAM2 |
結語
也是使用了很久的 QEMU 才對它的網路有了多一點瞭解,可以做出更複雜的應用。之前都是用 NAT + Port Forwarding 硬撐,用了 TAP 的確是多了一些樂趣,少了一些麻煩 (主要是不用設 port forwarding 了),以後也可以嚐試創造出更複雜的網路 topology。
您好, 謝謝您的分享, 很有用
但請問在方案一裡面
route add default gw 192.168.1.254
這裡192.168.1.254這個ip, 指的是您的host的ip, 還是您host執行ipconfig後, 看到的default gw ip(也就是host接的那台實體switch ip)呢?
192.168.1.254 是 ipconfig 看到的 default gw IP,這設定是要讓 host 可以連到外面的網路. 因為先前的 ifconfig eth0 0.0.0.0 會導致 default gw 的設定不見,所以才會需要再設一次。