虚拟机的网络是 KVM 里最容易让人迷糊的部分:virbr0 是什么、NAT 谁在做、桥接和 NAT 差在哪。本章把 libvirt 的三种网络模式(隔离、NAT、桥接)逐个讲透,每种都配上「在宿主机上看什么」的命令,把虚拟网络和计算机网络课的 IP/路由/转发知识(计网课第 5 章)对上号。读完这章,virsh domifaddr 查不到 IP 之类的问题你都能自己诊断。
| 模式 | VM 互通 | VM → 外网 | 外网 → VM | 典型用途 |
|---|---|---|---|---|
| 隔离(isolated) | 通 | 不通 | 不通 | 内网实验、安全测试 |
| NAT(默认) | 通 | 通 | 不通(端口映射可破) | 日常开发机 |
| 桥接(bridge) | 通 | 通 | 通(同一局域网) | 对外提供服务的 VM |
选型逻辑一句话:看 VM 要不要「被外面看见」。NAT 是默认,因为大多数 VM 是「消费者」(上网、下载、连外网服务);要当「服务者」(对外开端口)就上桥接。
第 2 章装完 libvirt 就存在的 default 网络就是 NAT 模式,和家用路由器原理一模一样:
virsh net-list --all
# Name State Autostart
# default active yes
virsh net-dumpxml default
# <ip address='192.168.122.1' netmask='255.255.255.0'>
# <dhcp>
# <range start='192.168.122.2' end='192.168.122.254'/>
拆解一下这套机制的每个零件,全部能在宿主机上亲眼看到:
ip link show virbr0 可见。ps aux | grep dnsmasq 可见。sudo iptables -t nat -L -n | grep 122 可见,计算机网络的 NAT 章节在此落地。所以 VM 能上网的秘密是「宿主机当了它的路由器」,外部主动连不进来,因为外部路由器不知道 192.168.122.x 这个私有网段(要进来就得在宿主机配端口转发,或者换桥接)。
诊断 NAT 网络问题的固定流程:VM 里 ip a 看拿到 IP 没(DHCP 挂了?)→ ping 192.168.122.1(通网桥了吗)→ ping 8.8.8.8(出网了吗,不通查转发)→ ping baidu.com(DNS 挂了?)。四步定位到具体环节。
连 NAT 都不要的纯内网(渗透测试、旧软件兼容实验),定义一个只有网桥没有上行转发 rule 的网络:
cat > iso.xml <<'EOF'
<network>
<name>iso</name>
</network>
EOF
virsh net-define iso.xml && virsh net-start iso && virsh net-autostart iso
VM 的 XML 里 <interface type='network'><source network='iso'/> 挂上去即可。VM 之间互通、与世隔绝,宿主机自己也不转发它们出网。这类网络常和「双网卡」搭配:VM 一张卡接 default(管理通道),一张接 iso(实验通道),两个世界互不干扰。
桥接把 VM 直接插进物理局域网:VM 从路由器拿到和宿主机同网段的 IP,外部可以直连它。代价是宿主机配置要动一下(把物理网卡变成网桥的从属端口):
# NetworkManager 方式(常见发行版默认)
sudo nmcli connection add type bridge ifname br0
sudo nmcli connection add type ethernet slave-type bridge \
con-name br0-port ifname enp1s0 master br0
sudo nmcli connection up br0
然后 VM 用 <interface type='bridge'><source bridge='br0'/>(或 virt-install --network bridge=br0)。VM 开机后 DHCP 从物理路由器拿地址,和宿主机平起平坐。
桥接的几个坑,提前踩好:其一,改网卡配置可能在 SSH 里断网(在控制台操作,或先配好桥再切);其二,无线网卡桥接很麻烦(802.11 的 MAC 过滤,多数环境要走 NAt 或 macvtap),桥接基本是有线场景的玩法;其三,公司/校园网可能限制一个端口多个 MAC(VM 的 MAC 会被丢包),那就只能回 NAT。
virsh domifaddr 查不到 IP。VM 还没开机/DHCP 没拿到/network 没挂对;进 console 用 ip a 直接看。/var/lib/libvirt/dnsmasq/default.leases),每个零件记录一条真实输出。sudo tcpdump -i virbr0 -n icmp 在宿主机抓包,VM 里 ping 外网,亲眼看 ICMP 包经过网桥;再换 arp 关键字看 DHCP 过程(计网课第 2、5 章的报文在自家网络里活捉)。