QEMU/高级网络
高级桥接网络配置
手动创建桥接
以下将描述如何将虚拟机桥接到主机接口(例如eth0),这可能是最常见的配置。此配置使得虚拟机看起来直接连接在外部网络上,与物理主机处于同一以太网段。
我们将用桥接适配器替换普通的以太网适配器,并将普通的以太网适配器绑定到它上面。
- 安装 bridge-utils,它提供了用于操作桥接的
brctl命令。
- 启用IPv4转发
# sysctl -w net.ipv4.ip_forward=1
要使更改永久生效,请在/etc/sysctl.d/99-sysctl.conf中将net.ipv4.ip_forward = 0更改为net.ipv4.ip_forward = 1。
- 加载
tun模块并配置其在启动时加载。详情请参阅 Kernel modules。
- 可选地创建桥接。详情请参阅 Bridge with netctl。请记住将桥接命名为
br0,或更改下面的脚本以匹配您的桥接名称。在下面的run-qemu脚本中,如果未列出br0,则会进行设置,因为默认情况下假设主机不通过桥接访问网络。
- 创建QEMU用于使用
root:kvm权限(750)启动tap适配器的脚本
/etc/qemu-ifup
#!/bin/sh echo "Executing /etc/qemu-ifup" echo "Bringing up $1 for bridged mode..." sudo /usr/bin/ip link set $1 up promisc on echo "Adding $1 to br0..." sudo /usr/bin/brctl addif br0 $1 sleep 2
- 在
/etc/qemu-ifdown中创建QEMU用于关闭tap适配器的脚本,并设置root:kvm权限(750)。
/etc/qemu-ifdown
#!/bin/sh echo "Executing /etc/qemu-ifdown" sudo /usr/bin/ip link set $1 down sudo /usr/bin/brctl delif br0 $1 sudo /usr/bin/ip link delete dev $1
- 使用
visudo将以下内容添加到您的sudoers文件中
Cmnd_Alias QEMU=/usr/bin/ip,/usr/bin/modprobe,/usr/bin/brctl %kvm ALL=NOPASSWD: QEMU
- 您可以使用以下
run-qemu脚本启动QEMU
run-qemu
#!/bin/bash
: '
e.g. with img created via:
qemu-img create -f qcow2 example.img 90G
run-qemu -cdrom archlinux-x86_64.iso -boot order=d -drive file=example.img,format=qcow2 -m 4G -enable-kvm -cpu host -smp 4
run-qemu -drive file=example.img,format=qcow2 -m 4G -enable-kvm -cpu host -smp 4
'
nicbr0() {
sudo ip link set dev $1 promisc on up &> /dev/null
sudo ip addr flush dev $1 scope host &>/dev/null
sudo ip addr flush dev $1 scope site &>/dev/null
sudo ip addr flush dev $1 scope global &>/dev/null
sudo ip link set dev $1 master br0 &> /dev/null
}
_nicbr0() {
sudo ip link set $1 promisc off down &> /dev/null
sudo ip link set dev $1 nomaster &> /dev/null
}
HASBR0="$( ip link show | grep br0 )"
if [ -z $HASBR0 ] ; then
ROUTER="192.168.1.1"
SUBNET="192.168.1."
NIC=$(ip link show | grep en | grep 'state UP' | head -n 1 | cut -d":" -f 2 | xargs)
IPADDR=$(ip addr show | grep -o "inet $SUBNET\([0-9]*\)" | cut -d ' ' -f2)
sudo ip link add name br0 type bridge &> /dev/null
sudo ip link set dev br0 up
sudo ip addr add $IPADDR/24 brd + dev br0
sudo ip route del default &> /dev/null
sudo ip route add default via $ROUTER dev br0 onlink
nicbr0 $NIC
sudo iptables -I FORWARD -m physdev --physdev-is-bridged -j ACCEPT
fi
USERID=$(whoami)
precreationg=$(ip tuntap list | cut -d: -f1 | sort)
sudo ip tuntap add user $USERID mode tap
postcreation=$(ip tuntap list | cut -d: -f1 | sort)
TAP=$(comm -13 <(echo "$precreationg") <(echo "$postcreation"))
nicbr0 $TAP
printf -v MACADDR "52:54:%02x:%02x:%02x:%02x" $(( $RANDOM & 0xff)) $(( $RANDOM & 0xff )) $(( $RANDOM & 0xff)) $(( $RANDOM & 0xff ))
qemu-system-x86_64 -net nic,macaddr=$MACADDR,model=virtio \
-net tap,ifname=$TAP,script=no,downscript=no,vhost=on \
$@
_nicbr0 $TAP
sudo ip link set dev $TAP down &> /dev/null
sudo ip tuntap del $TAP mode tap
if [ -z $HASBR0 ] ; then
_nicbr0 $NIC
sudo ip addr del dev br0 $IPADDR/24 &> /dev/null
sudo ip link set dev br0 down
sudo ip link delete br0 type bridge &> /dev/null
sudo ip route del default &> /dev/null
sudo ip link set dev $NIC up
sudo ip route add default via $ROUTER dev $NIC onlink &> /dev/null
fi
然后,要启动虚拟机,可以执行类似以下操作:
$ run-qemu -hda myvm.img -m 512
- 出于性能和安全原因,建议禁用桥接上的防火墙。
/etc/sysctl.d/10-disable-firewall-on-bridge.conf
net.bridge.bridge-nf-call-ip6tables = 0 net.bridge.bridge-nf-call-iptables = 0 net.bridge.bridge-nf-call-arptables = 0
为了在启动时应用上述参数,您还需要在启动时加载br-netfilter模块。否则,当sysctl尝试修改这些参数时,它们将不存在。
/etc/modules-load.d/br_netfilter.conf
br_netfilter
运行sysctl -p /etc/sysctl.d/10-disable-firewall-on-bridge.conf以立即应用更改。
请参阅 libvirt wiki 和 Fedora bug 512206。如果在启动时遇到关于不存在文件的sysctl错误,请确保bridge模块在启动时加载。详情请参阅 Kernel module#systemd。
或者,您可以配置 iptables,通过添加以下规则允许所有流量在桥接上传输:
-I FORWARD -m physdev --physdev-is-bridged -j ACCEPT
通过iptables在物理设备和Tap设备之间共享网络
桥接网络在有线接口(例如eth0)之间可以正常工作,并且易于设置。但是,如果主机通过无线设备连接到网络,则无法进行桥接。
请参阅 Network bridge#无线接口桥接 作为参考。
克服这一问题的一种方法是设置一个带有静态IP的tap设备,让Linux自动处理其路由,然后通过iptables规则在tap接口和连接到网络的设备之间转发流量。
请参阅 Internet sharing 作为参考。
在那里,您可以找到共享网络设备所需的信息,包括tap和tun设备。以下只是进一步提示了一些所需的主机配置。如上文参考所示,客户端需要配置为静态IP,并将分配给tap接口的IP用作网关。需要注意的是,客户端的DNS服务器在更改连接到网络的宿主设备时可能需要手动编辑。
为了允许每次启动时都进行IP转发,需要在/etc/sysctl.d内的sysctl配置文件中添加以下行:
net.ipv4.ip_forward = 1 net.ipv6.conf.default.forwarding = 1 net.ipv6.conf.all.forwarding = 1
iptables规则可以如下所示:
# Forwarding from/to outside
iptables -A FORWARD -i ${INT} -o ${EXT_0} -j ACCEPT
iptables -A FORWARD -i ${INT} -o ${EXT_1} -j ACCEPT
iptables -A FORWARD -i ${INT} -o ${EXT_2} -j ACCEPT
iptables -A FORWARD -i ${EXT_0} -o ${INT} -j ACCEPT
iptables -A FORWARD -i ${EXT_1} -o ${INT} -j ACCEPT
iptables -A FORWARD -i ${EXT_2} -o ${INT} -j ACCEPT
# NAT/Masquerade (network address translation)
iptables -t nat -A POSTROUTING -o ${EXT_0} -j MASQUERADE
iptables -t nat -A POSTROUTING -o ${EXT_1} -j MASQUERADE
iptables -t nat -A POSTROUTING -o ${EXT_2} -j MASQUERADE
以上假设有3个设备连接到网络,并与一个内部设备共享流量,例如:
INT=tap0 EXT_0=eth0 EXT_1=wlan0 EXT_2=tun0
以上展示了允许有线和无线连接与tap设备共享的转发。
显示的转发规则是无状态的,并且仅用于纯转发。可以考虑限制特定流量,放置防火墙来保护客户机等。然而,这将降低网络性能,而简单的桥接则不包含这些。
附加:无论连接是有线还是无线,如果通过VPN连接到带有tun设备的远程站点,假设打开VPN连接的tun设备是tun0,并且应用了上述iptables规则,那么远程连接也将与客户机共享。这避免了客户机也需要打开VPN连接的需要。同样,由于客户机网络需要是静态的,那么当宿主通过这种方式远程连接时,很可能需要编辑客户机上的DNS服务器。
使用VDE2进行网络配置
什么是VDE?
VDE代表Virtual Distributed Ethernet。它最初是uml_switch的增强。它是一套用于管理虚拟网络的工具集。
其思想是创建虚拟交换机,这些交换机本质上是套接字,并将物理机和虚拟机“插入”其中。我们此处展示的配置非常简单;然而,VDE的功能远不止于此,它可以连接虚拟交换机,在不同主机上运行它们,并监控交换机中的流量。您可以阅读 该项目的文档。
这种方法的优点是您无需为用户添加sudo权限。普通用户不应被允许运行modprobe。
基础知识
在我们的配置中,我们使用tun/tap在主机上创建一个虚拟接口。加载tun模块(详情请参阅 Kernel modules)。
# modprobe tun
现在创建虚拟交换机
# vde_switch -tap tap0 -daemon -mod 660 -group users
此行创建交换机,创建tap0,将其“插入”并允许users组的用户使用它。
接口已插入但尚未配置。要配置它,请运行此命令:
# ip addr add 192.168.100.254/24 dev tap0
现在,您只需以普通用户身份运行KVM并使用这些-net选项:
$ qemu-system-x86_64 -net nic -net vde -hda [...]
像在物理网络中一样配置您的客户机的网络。
启动脚本
启动VDE的主脚本示例
/etc/systemd/scripts/qemu-network-env
#!/bin/sh
# QEMU/VDE network environment preparation script
# The IP configuration for the tap device that will be used for
# the virtual machine network:
TAP_DEV=tap0
TAP_IP=192.168.100.254
TAP_MASK=24
TAP_NETWORK=192.168.100.0
# Host interface
NIC=eth0
case "$1" in
start)
echo -n "Starting VDE network for QEMU: "
# If you want tun kernel module to be loaded by script uncomment here
#modprobe tun 2>/dev/null
## Wait for the module to be loaded
#while ! lsmod | grep -q "^tun"; do echo "Waiting for tun device"; sleep 1; done
# Start tap switch
vde_switch -tap "$TAP_DEV" -daemon -mod 660 -group users
# Bring tap interface up
ip address add "$TAP_IP"/"$TAP_MASK" dev "$TAP_DEV"
ip link set "$TAP_DEV" up
# Start IP Forwarding
echo "1" > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -s "$TAP_NETWORK"/"$TAP_MASK" -o "$NIC" -j MASQUERADE
;;
stop)
echo -n "Stopping VDE network for QEMU: "
# Delete the NAT rules
iptables -t nat -D POSTROUTING -s "$TAP_NETWORK"/"$TAP_MASK" -o "$NIC" -j MASQUERADE
# Bring tap interface down
ip link set "$TAP_DEV" down
# Kill VDE switch
pgrep vde_switch | xargs kill -TERM
;;
restart|reload)
$0 stop
sleep 1
$0 start
;;
*)
echo "Usage: $0 {start|stop|restart|reload}"
exit 1
esac
exit 0
使用上述脚本的systemd服务示例
/etc/systemd/system/qemu-network-env.service
[Unit] Description=Manage VDE Switch [Service] Type=oneshot ExecStart=/etc/systemd/scripts/qemu-network-env start ExecStop=/etc/systemd/scripts/qemu-network-env stop RemainAfterExit=yes [Install] WantedBy=multi-user.target
更改qemu-network-env的权限,使其变为可执行。
您可以像往常一样启动qemu-network-env.service。
替代方法
如果上述方法不起作用,或者您不想折腾内核配置、TUN、dnsmasq和iptables,您可以执行以下操作来实现相同的结果:
# vde_switch -daemon -mod 660 -group users # slirpvde --dhcp --daemon
然后,要启动虚拟机以连接到主机的网络:
$ qemu-system-x86_64 -net nic,macaddr=52:54:00:00:EE:03 -net vde disk_image
VDE2桥接
基于 quickhowto: qemu networking using vde, tun/tap, and bridge 图。连接到vde的任何虚拟机都将暴露在外部。例如,每台虚拟机都可以直接从您的ADSL路由器接收DHCP配置。
基础知识
请记住,您需要tun模块和 bridge-utils 包。
创建vde2/tap设备
# vde_switch -tap tap0 -daemon -mod 660 -group users # ip link set tap0 up
创建桥接
# brctl addbr br0
添加设备
# brctl addif br0 eth0 # brctl addif br0 tap0
并配置桥接接口
# dhcpcd br0
启动脚本
所有设备都必须设置。只有桥接需要IP地址。对于桥接上的物理设备(例如eth0),可以使用netctl通过自定义以太网配置文件来完成:
/etc/netctl/ethernet-noip
Description='A more versatile static Ethernet connection' Interface=eth0 Connection=ethernet IP=no
以下自定义systemd服务可用于为users用户组中的用户创建和激活VDE2 tap接口。
/etc/systemd/system/vde2@.service
[Unit] Description=Network Connectivity for %i Wants=network.target Before=network.target [Service] Type=oneshot RemainAfterExit=yes ExecStart=/usr/bin/vde_switch -tap %i -daemon -mod 660 -group users ExecStart=/usr/bin/ip link set dev %i up ExecStop=/usr/bin/ip addr flush dev %i ExecStop=/usr/bin/ip link set dev %i down [Install] WantedBy=multi-user.target