05 - 网络配置
05 - 网络配置
掌握 QEMU 的各种网络模式:用户模式、桥接、TAP、NAT、多网卡配置与 PCI 网络直通。
5.1 QEMU 网络模式概览
| 模式 | 性能 | 外部访问 | 配置难度 | 适用场景 |
|---|---|---|---|---|
| 用户模式 (SLIRP) | 低 | ❌ 虚拟机不可被外部访问 | 最简单 | 快速测试 |
| TAP/桥接 | 高 | ✅ | 中等 | 生产环境 |
| Socket | 中等 | 局域网内 | 中等 | 虚拟机间通信 |
| 多播 | 中等 | 局域网内 | 中等 | 虚拟机组通信 |
| PCI 直通 | 最高 | ✅ | 复杂 | 高性能网络 |
5.2 用户模式网络(User Mode / SLIRP)
用户模式是 QEMU 默认的网络模式,无需任何特权配置:
# 基本用户模式网络
qemu-system-x86_64 \
-enable-kvm -cpu host -m 2G \
-drive file=vm.qcow2,format=qcow2 \
-netdev user,id=net0 \
-device virtio-net-pci,netdev=net0
# 等价的旧语法
qemu-system-x86_64 ... -net nic -net user
用户模式网络特性
用户模式网络架构:
┌─────────────────┐
│ Guest VM │
│ 10.0.2.15 │
│ 网关: 10.0.2.2 │
│ DNS: 10.0.2.3 │
└────────┬────────┘
│ SLIRP (用户态网络栈)
┌────────┴────────┐
│ QEMU 进程 │
└────────┬────────┘
│ NAT
┌────────┴────────┐
│ 宿主机网络 │
└─────────────────┘
| 特性 | 值 |
|---|---|
| 虚拟机 IP | 10.0.2.15(固定) |
| 网关 | 10.0.2.2 |
| DNS | 10.0.2.3 |
| DHCP | 内置(自动分配 10.0.2.15) |
| 外部访问 | ✅ 可以访问外部网络 |
| 外部访问虚拟机 | ❌ 需要端口转发 |
端口转发
# SSH 端口转发
qemu-system-x86_64 \
-netdev user,id=net0,hostfwd=tcp::2222-:22 \
-device virtio-net-pci,netdev=net0
# 连接: ssh -p 2222 user@localhost
# 多端口转发
qemu-system-x86_64 \
-netdev user,id=net0,\
hostfwd=tcp::2222-:22,\
hostfwd=tcp::8080-:80,\
hostfwd=tcp::8443-:443,\
hostfwd=udp::5353-:53 \
-device virtio-net-pci,netdev=net0
# 反向端口转发(虚拟机访问宿主机端口)
qemu-system-x86_64 \
-netdev user,id=net0,\
hostfwd=tcp::2222-:22,\
guestfwd=tcp:10.0.2.100:80-tcp:192.168.1.50:8080 \
-device virtio-net-pci,netdev=net0
自定义 DHCP 与 TFTP
# 自定义 DHCP 范围
qemu-system-x86_64 \
-netdev user,id=net0,\
net=192.168.100.0/24,\
dhcpstart=192.168.100.100,\
host=192.168.100.1 \
-device virtio-net-pci,netdev=net0
# 启用内置 TFTP 服务器(PXE 启动用)
qemu-system-x86_64 \
-netdev user,id=net0,tftp=/var/lib/tftpboot,bootfile=/pxelinux.0 \
-device virtio-net-pci,netdev=net0
# 指定 DNS 和域名
qemu-system-x86_64 \
-netdev user,id=net0,dnssearch=example.com,dns=8.8.8.8 \
-device virtio-net-pci,netdev=net0
用户模式网络限制
性能瓶颈: 用户模式网络运行在用户态,所有网络包需要经过内核→用户态→内核的转换,吞吐量通常只有 200-500 Mbps。
不支持多播: 用户模式不支持多播和广播,某些依赖这些特性的协议无法正常工作。
不支持 ICMP: 无法在虚拟机内 ping 外部主机(可以使用 TCP/UDP)。
5.3 TAP 网络
TAP 设备是最灵活和高性能的网络方案,它创建一个虚拟的以太网设备,可以与桥接配合使用:
# 创建 TAP 设备
sudo ip tuntap add dev tap0 mode tap user $(whoami)
sudo ip link set tap0 up
# 将 TAP 设备加入桥接
sudo ip link set tap0 master br0
使用 TAP 设备启动 QEMU
# 方法 1:手动管理 TAP 设备
qemu-system-x86_64 \
-enable-kvm -cpu host -m 2G \
-drive file=vm.qcow2,format=qcow2 \
-netdev tap,id=net0,ifname=tap0,script=no,downscript=no \
-device virtio-net-pci,netdev=net0,mac=52:54:00:12:34:56
使用自动脚本管理 TAP
# /etc/qemu-ifup
#!/bin/bash
switch=br0
if [ -n "$1" ]; then
# 创建或使用已有的 TAP 设备
ip link set $1 up
ip link set $1 master ${switch}
echo "TAP 设备 $1 已加入桥接 ${switch}"
fi
# /etc/qemu-ifdown
#!/bin/bash
switch=br0
if [ -n "$1" ]; then
ip link set $1 nomaster
ip link set $1 down
echo "TAP 设备 $1 已从桥接 ${switch} 移除"
fi
# 使用自动脚本(默认脚本路径)
qemu-system-x86_64 \
-enable-kvm -cpu host -m 2G \
-drive file=vm.qcow2,format=qcow2 \
-netdev tap,id=net0,script=/etc/qemu-ifup,downscript=/etc/qemu-ifdown \
-device virtio-net-pci,netdev=net0
多 TAP 设备
# 启动多个虚拟机,每个使用不同的 TAP 设备
# VM1: tap0
qemu-system-x86_64 -netdev tap,id=net0,ifname=tap0,script=no,downscript=no \
-device virtio-net-pci,netdev=net0 &
# VM2: tap1
qemu-system-x86_64 -netdev tap,id=net0,ifname=tap1,script=no,downscript=no \
-device virtio-net-pci,netdev=net0 &
5.4 桥接网络
桥接网络让虚拟机像物理机一样直接接入局域网:
桥接网络架构:
┌───────────────┐ ┌───────────────┐
│ VM1 │ │ VM2 │
│ 192.168.1.101 │ │ 192.168.1.102 │
│ (tap0) │ │ (tap1) │
└───────┬───────┘ └───────┬───────┘
│ │
┌───────┴────────────────────┴───────┐
│ 桥接 br0 │
│ 192.168.1.100 │
└───────────────┬───────────────────┘
│
┌───────────────┴───────────────────┐
│ 物理网卡 eth0 │
└───────────────┬───────────────────┘
│
┌───────┴───────┐
│ 交换机/路由器 │
│ 192.168.1.1 │
└───────────────┘
完整桥接配置脚本
#!/bin/bash
# setup-bridge.sh - 配置 QEMU 桥接网络
PHYS_IF="enp0s3" # 物理网卡
BRIDGE_IF="br0" # 桥接接口
BRIDGE_IP="192.168.1.100/24"
BRIDGE_GW="192.168.1.1"
# 安装依赖
# sudo apt install bridge-utils
# 创建桥接
sudo ip link add name ${BRIDGE_IF} type bridge
sudo ip link set ${BRIDGE_IF} up
# 将物理网卡的 IP 移到桥接
sudo ip addr flush dev ${PHYS_IF}
sudo ip addr add ${BRIDGE_IP} dev ${BRIDGE_IF}
sudo ip route add default via ${BRIDGE_GW} dev ${BRIDGE_IF}
# 将物理网卡加入桥接
sudo ip link set ${PHYS_IF} master ${BRIDGE_IF}
echo "桥接配置完成"
ip addr show ${BRIDGE_IF}
使用 systemd-networkd 配置桥接
# /etc/systemd/network/10-br0.netdev
[NetDev]
Name=br0
Kind=bridge
# /etc/systemd/network/20-br0-enp0s3.network
[Match]
Name=enp0s3
[Network]
Bridge=br0
# /etc/systemd/network/30-br0.network
[Match]
Name=br0
[Network]
DHCP=yes
# 或者静态 IP
# Address=192.168.1.100/24
# Gateway=192.168.1.1
# DNS=8.8.8.8
sudo systemctl restart systemd-networkd
5.5 NAT 网络
NAT 网络让虚拟机通过 NAT 访问外部网络,但外部无法主动访问虚拟机:
# 创建 NAT 网络桥接
sudo ip link add virbr0 type bridge
sudo ip addr add 192.168.122.1/24 dev virbr0
sudo ip link set virbr0 up
# 启用 IP 转发
sudo sysctl -w net.ipv4.ip_forward=1
# 配置 iptables NAT 规则
sudo iptables -t nat -A POSTROUTING -s 192.168.122.0/24 -o enp0s3 -j MASQUERADE
sudo iptables -A FORWARD -i virbr0 -o enp0s3 -j ACCEPT
sudo iptables -A FORWARD -i enp0s3 -o virbr0 -m state --state RELATED,ESTABLISHED -j ACCEPT
# 启动虚拟机,使用 NAT 桥接
qemu-system-x86_64 \
-enable-kvm -cpu host -m 2G \
-drive file=vm.qcow2,format=qcow2 \
-netdev tap,id=net0,ifname=tap0,script=no,downscript=no \
-device virtio-net-pci,netdev=net0
# 配置 TAP 设备
sudo ip link set tap0 master virbr0
sudo ip link set tap0 up
# 在虚拟机中配置 IP 192.168.122.x,网关 192.168.122.1
使用 dnsmasq 提供 DHCP/DNS
# 安装 dnsmasq
sudo apt install dnsmasq
# 配置 dnsmasq
cat > /etc/dnsmasq.d/qemu-nat.conf << 'EOF'
interface=virbr0
bind-interfaces
dhcp-range=192.168.122.100,192.168.122.200,255.255.255.0,12h
dhcp-option=option:router,192.168.122.1
dhcp-option=option:dns-server,8.8.8.8,8.8.4.4
domain=qemu.local
EOF
sudo systemctl restart dnsmasq
5.6 多网卡配置
# 虚拟机配置多个网卡
qemu-system-x86_64 \
-enable-kvm -cpu host -m 4G \
-drive file=vm.qcow2,format=qcow2 \
-netdev user,id=mgmt,hostfwd=tcp::2222-:22 \
-device virtio-net-pci,netdev=mgmt,mac=52:54:00:00:00:01 \
-netdev tap,id=data0,ifname=tap0,script=no,downscript=no \
-device virtio-net-pci,netdev=data0,mac=52:54:00:00:00:02 \
-netdev tap,id=data1,ifname=tap1,script=no,downscript=no \
-device virtio-net-pci,netdev=data1,mac=52:54:00:00:00:03
网络用途划分示例
多网卡典型架构:
┌───────────────────────────────────────────┐
│ Virtual Machine │
│ │
│ eth0 (管理网) eth1 (业务网) │
│ 10.0.0.10 192.168.100.10 │
│ NAT/用户模式 TAP/桥接 │
├───────────────────────────────────────────┤
│ 用于 SSH 管理 用于数据传输 │
└───────────────────────────────────────────┘
| 网卡 | 模式 | 用途 | 安全 |
|---|---|---|---|
| eth0 | 用户模式 | 管理(SSH) | 仅本机访问 |
| eth1 | TAP/桥接 | 业务数据 | 局域网访问 |
| eth2 | TAP/桥接 | 存储网络 | 专用网络 |
5.7 网络性能优化
vhost-net 加速
vhost-net 将网络数据处理从用户态移到内核态,大幅提升性能:
# 加载 vhost_net 模块
sudo modprobe vhost_net
# 使用 vhost-net 启动
qemu-system-x86_64 \
-enable-kvm -cpu host -m 2G \
-drive file=vm.qcow2,format=qcow2 \
-netdev tap,id=net0,vhost=on,script=no,downscript=no \
-device virtio-net-pci,netdev=net0
# 或使用 vhost-user(需 DPDK/OVS 支持)
qemu-system-x86_64 \
-netdev type=vhost-user,id=net0,chardev=char0,vhostforce=on \
-chardev socket,id=char0,path=/var/run/openvswitch/vhost-user0 \
-device virtio-net-pci,netdev=net0
网络多队列
# 使用多队列提高多核 CPU 的网络吞吐
qemu-system-x86_64 \
-smp 4 \
-netdev tap,id=net0,vhost=on,queues=4,script=no,downscript=no \
-device virtio-net-pci,netdev=net0,mq=on,vectors=8
# 在客户机中启用多队列
# 对于 eth0
ethtool -L eth0 combined 4
网络性能对比
| 方案 | 吞吐量 (Gbps) | CPU 开销 | 延迟 |
|---|---|---|---|
| 用户模式 | 0.2-0.5 | 低 | 高 |
| TAP + virtio | 5-10 | 中等 | 低 |
| TAP + vhost-net | 10-20 | 低 | 最低 |
| PCI 直通 | 20+ (线速) | 最低 | 最低 |
5.8 网络故障排查
检查网络连通性
# 在宿主机检查 TAP 设备
ip link show tap0
# 检查桥接状态
bridge link show
brctl show # 旧命令
# 在虚拟机内检查
ip addr show
ip route show
ping -c 3 192.168.1.1 # ping 网关
ping -c 3 8.8.8.8 # ping 外部
nslookup google.com # DNS 解析测试
常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 虚拟机无法上网 | 网关或 DNS 配置错误 | 检查 IP/网关/DNS 配置 |
| 无法 SSH 到虚拟机 | 端口转发未配置 | 添加 hostfwd 参数 |
| TAP 设备无法通信 | 桥接未正确配置 | 检查 ip link set master |
| 性能很差 | 未使用 vhost-net | 添加 vhost=on 参数 |
| MAC 地址冲突 | 多个虚拟机使用相同 MAC | 为每个网卡指定唯一 MAC |
tcpdump 抓包
# 在宿主机抓取 TAP 设备的包
sudo tcpdump -i tap0 -nn -vv
# 抓取桥接上的包
sudo tcpdump -i br0 -nn -vv
# 保存到文件用 Wireshark 分析
sudo tcpdump -i tap0 -w /tmp/qemu-traffic.pcap
5.9 PCI 网络直通
将物理网卡直通给虚拟机,获得接近原生的网络性能:
# 查找网卡的 PCI 地址
lspci | grep -i ethernet
# 将网卡绑定到 vfio-pci 驱动
# 假设网卡 PCI 地址为 03:00.0
echo "vfio-pci" | sudo tee /sys/bus/pci/devices/0000:03:00.0/driver_override
echo "0000:03:00.0" | sudo tee /sys/bus/pci/devices/0000:03:00.0/driver/unbind
echo "0000:03:00.0" | sudo tee /sys/bus/pci/drivers/vfio-pci/bind
# 启动虚拟机并直通网卡
qemu-system-x86_64 \
-enable-kvm -cpu host -m 4G \
-drive file=vm.qcow2,format=qcow2 \
-device vfio-pci,host=03:00.0
详细的设备直通配置请参见 第 10 章 - 设备直通。
要点回顾
| 要点 | 核心内容 |
|---|---|
| 用户模式 | 最简单,无需特权,性能低,适合测试 |
| TAP/桥接 | 高性能,需要 root 权限,适合生产 |
| NAT | 通过 iptables 实现,虚拟机不暴露给外部 |
| 多网卡 | 管理网 + 业务网分离,增强安全性 |
| vhost-net | 将网络处理移入内核,性能提升 2-3 倍 |
注意事项
MAC 地址管理: 如果不指定 MAC 地址,QEMU 会随机生成。在桥接网络中,建议固定 MAC 地址以获得稳定的 DHCP 分配。
防火墙规则: 桥接网络可能被 iptables/nftables 规则阻挡。检查
iptables -L -n确保桥接流量被正确放行。
MTU 配置: 使用巨帧(Jumbo Frame)时,宿主机网卡、桥接接口、TAP 设备和虚拟机网卡的 MTU 必须一致。
扩展阅读
下一步
→ 06 - 快照管理:深入学习内部快照、外部快照、实时快照与自动化管理。