QEMU网络--桥接网络、tap设备

QEMU 可以使用 TAP 接口为GuestOS提供完整的网络功能。 当GuestOS运行多个网络服务并且必须通过标准端口连接时,这可能很有用,还比如需要 TCP 和 UDP 以外的协议时,以及 QEMU 的多个实例需要相互连接的时候尽管这也可以在用户模式网络中通过端口重定向或通过套接字来实现)。

采用TAP设备和网桥的虚拟网络的性能应该会比使用用户模式网络或VDE要好,原因在于TAP设备和网桥是在内核中实现的。

首先创建tun、tap设备。

$ sudo mkdir /dev/net

$ sudo mknod /dev/net/tun c 10 200

$ sudo /sbin/modprobe tun

检测到有/dev/net/tun设备文件即可。

接下来使用使用qemu启动虚拟机时,可以使用qemu提供的bash脚本来创建tap设备等,来加入到桥接网络。下面分析qemu提供的bash脚本,来了解如何构建使一个虚拟机加入到桥接网络。

qemu-ifup

下面是脚本qemu-ifup,用来创建网桥,并以网桥模式启动tun设备,脚本的第一个参数是tap设备名,如tap0。(注记不需要自己创建好tap设备,由脚本创建)

#!/bin/sh 
# 
# script to bring up the tun device in QEMU in bridged mode 
# first parameter is name of tap device (e.g. tap0)
#
# some constants specific to the local host - change to suit your host
#主机的一个常量信息,需要修改
# ETH0IPADDR:eth0 ip addr
#
ETH0IPADDR=192.168.0.3		
MASK=255.255.255.0
GATEWAY=192.168.0.1
BROADCAST=192.168.0.255
#
# First take eth0 down, then bring it up with IP address 0.0.0.0 
#将eth0的ip分配给br0,因为eth0绑定到网桥后,它的ip就没用了。
/sbin/ifdown eth0
/sbin/ifconfig eth0 0.0.0.0 promisc up
#
# Bring up the tap device (name specified as first argument, by QEMU)
#创建tap设备,可以改为使用tunctl命令来创建启动tap设备
/usr/sbin/openvpn --mktun --dev $1 --user `id -un`
/sbin/ifconfig $1 0.0.0.0 promisc up
#
# create the bridge between eth0 and the tap device
#
/usr/sbin/brctl addbr br0
/usr/sbin/brctl addif br0 eth0
/usr/sbin/brctl addif br0 $1
# 
# only a single bridge so loops are not possible, turn off spanning tree protocol
#只有一个网桥,因此不可能发生循环,关闭stp协议
#
/usr/sbin/brctl stp br0 off 
# 
# Bring up the bridge with ETH0IPADDR and add the default route 
#给网桥分配eth0的ip,eth0拿着ip没用,eth0起到连接网关的作用。还要给添加一条默认路由,使得ubuntu主机中发往外网数据包往br0走,而不是往eth0走,eth0没法连通外网。
/sbin/ifconfig br0 $ETH0IPADDR netmask $MASK broadcast $BROADCAST
/sbin/route add default gw $GATEWAY
#
# stop firewall - comment this out if you don't use Firestarter
#关闭防火墙
#
/sbin/service firestarter stop 

qemu-ifdown

退出qemu后需要重置一下网络配置。

#!/bin/sh 
# 
# Script to bring down and delete bridge br0 when QEMU exits 
# 
# Bring down eth0 and br0 
#
/sbin/ifdown eth0
/sbin/ifdown br0
/sbin/ifconfig br0 down 
# 
# Delete the bridge
#
/usr/sbin/brctl delbr br0 
# 
# bring up eth0 in "normal" mode 
#
/sbin/ifconfig eth0 -promisc
/sbin/ifup eth0 
#
# delete the tap device
#
/usr/sbin/openvpn --rmtun --dev $1
#
# start firewall again
# 
/sbin/service firestarter start 

注意:编写自定义的脚本传给script、downscript参数时,脚本入参也是要求有一个参数tap设备名。

下面执行手动执行命令来配置网络环境,然后不使用qemu的启动脚本。

主机中执行完这些命令

sudo brctl addbr br0

sudo ip addr flush dev ens36

sudo tunctl -t tap0 -u snowflakes

sudo brctl addif br0 ens36

sudo brctl addif br0 tap0

sudo ifconfig ens36 up

sudo ifconfig tap0 up

sudo ifconfig br0 up

sudo ifconfig br0 192.168.150.160 netmask 255.255.255.0 broadcast 192.168.150.255

sudo route add default gw 192.168.150.2

sudo sysctl net.bridge.bridge-nf-call-iptables=0

sudo sysctl net.bridge.bridge-nf-call-iptables=0

启动虚拟机的执行命令如下

sudo qemu-system-x86_64 -m 2048 -enable-kvm -net nic -net tap,ifname=tap0,script=no,downscript=no vm.img

如下图可见,ping主机、ping外网都可以了!与主机处于同一个网络。

新开一个虚拟机的话,需要新创建对应的tap设备。

sudo tunctl -t tap1 -u snowflakes

sudo brctl addif br0 tap1

sudo ifconfig tap1 up

启动命令也改成使用tap1设备。

sudo qemu-system-x86_64 -m 2048 -enable-kvm -net nic -net tap,ifname=tap1,script=no,downscript=no vm2.img

这样的虚拟机也能跟外网、主机连通!但是,跟刚才那台虚拟机无法互相连通!因为它们拥有相同的mac地址,网桥无法正常工作。

因此需要设置不同的mac地址。

sudo qemu-system-x86_64 -m 2048 -enable-kvm -net nic,macaddr=52:54:00:12:34:57 -net tap,ifname=tap1,script=no,downscript=no vm2.img

用户可以从windows主机连接进虚拟机,用户之间也可以互相访问到。

如果想要把启动命令写成一个脚本,然后通过qemu的启动参数配置来调用它,从而自动配置环境,则如下(注意:网桥br0需要已经创建好,而不是在脚本里创建):

自定义script参数的脚本create_tap.sh如下:

#!/bin/bash

#check for the input args
if [[ $# != 1 ]]
then
 echo "USAGE: create_tap.sh tapName "
  exit 1
fi

tapName=$1
passwd="***"
admin="snowflakes"   
echo $passwd | sudo -S tunctl -t $tapName -u $admin
sudo brctl addif br0 $tapName
sudo ifconfig $tapName up

downscript参数的脚本remove_tap.sh如下:

#!/bin/bash

#check for the input args
if [[ $# != 1 ]]
then
 echo "USAGE: remove_tap.sh tapName "
  exit 1
fi

tapName=$1
passwd="210484"
echo $passwd | sudo -S tunctl -d $tapName

执行命令启动虚拟机时

qemu-system-x86_64 -enable-kvm -m 2048  vm.img -net nic,macaddr=52:54:00:12:34:56 -net tap,ifname=tap0,script=./scripts/create_tap.sh,downscript=./scripts/remove_tap.sh 

会报如下错误。

TUNSETIFF: Device or resource busy

但是启动后的虚拟机也能正常使用,tap设备也按照预期配置好了。

这个报错是因为:

(I dont know from when), qemu will create the tap first and then call your /etc/qemu-ifup script. So you see the error report, just because the same tap already exists.

qemu不知道从什么时候开始,自动给用户创建好tap设备,然后才执行script脚本,自动给用户删除tap设备,然后才执行downscript脚本,因此会报上面的错误,但是功能上不影响。

那么把调用参数改成如下

script=./scripts/create_tap.sh,downscript=no

create_tap.sh这一行注释掉

#echo $passwd | sudo -S tunctl -t $tapName -u $admin

这样的话,执行就不会报错了。

猜你喜欢

转载自blog.csdn.net/m0_43406494/article/details/124828283
今日推荐