libvirt NAT型网络

Libvirt的NAT网络是针对只需要外出流量的IPv4网络的虚拟机,libvirt服务器作为一个路由器,所有VM流量对外显示成从这个服务器的IPv4地址发出。

默认的虚拟机网络就是一个NAT网络(具备 fragile hook system 来转发进入的连接)。但是,NAT网络引入了iptables规则,所以难以控制,除非你已经完全禁止默认网络。如果你需要完全控制并避免libvirt介入,则参考 libvirt 定制NAT型网络

Host主机配置

每个标准的libvirt安装会提供虚拟机连接外部的NAT虚拟网络,这个NAT虚拟网络也称为”default virtual network”,可以通过以下命令检查:

virsh net-list --all

输出可以看到:

Name                 State      Autostart
-----------------------------------------
default              active     yes

如果libvirt安装时没有创建默认NAT虚拟网络,可以通过example的XML配置重新加载和激活:

virsh net-define /usr/share/libvirt/networks/default.xml

如果没有上述案例配置文件,可以从其他正确安装NAT虚拟网络的主机上使用命令 virsh net-edit default 查看标准的配置:

<network>
  <name>default</name>
  <bridge name="virbr0"/>
  <forward mode="nat"/>
  <ip address="192.168.122.1" netmask="255.255.255.0">
    <dhcp>
      <range start="192.168.122.2" end="192.168.122.254"/>
    </dhcp>
  </ip>
</network>

然后执行如下命令定义:

virsh net-define /tmp/default.xml

在Arch Linux实践KVM时候,检查发现默认default网络没有激活(最初安装libvirt时没有同时安装bridge-utils):

# virsh net-list --all
 Name      State      Autostart   Persistent
----------------------------------------------
 default   inactive   no          yes

启动default网络:

virsh net-start default

报错显示,NAT网络依赖防火墙后端:

error: Failed to start network default
error: internal error: Failed to initialize a valid firewall backend

参考 libvirt: “Failed to initialize a valid firewall backend” 上述报错是因为没有安装firewalld软件包,即使此时系统已经安装了 ebtables, dnsmasq libvirt iptables:

$ pacman -Q ebtables dnsmasq libvirt iptables
ebtables 2.0.10_4-7
dnsmasq 2.80-4
libvirt 5.5.0-1
iptables 1:1.8.3-1

修复方法如下:

sudo pacman -Syu ebtables dnsmasq firewalld
sudo systemctl start firewalld
sudo systemctl enable firewalld
sudo systemctl restart libvirtd

现在就可以启动default网络了:

virsh net-start default

然后设置default NAT虚拟网路默认启动:

virsh net-autostart default

当默认的NAT网络启动后,你会看到一个隔离的bridge设备,这个设备 没有 任何物理网络接口连接,所以它使用的是 NAT+forwarding 来连接外部网络。请不要添加任何网络接口!!!

检查:

brctl show

显示:

bridge name  bridge id               STP enabled     interfaces
virbr0       8000.7a5026bf337c       yes             virbr0-nic

libvirt会添加iptables规则INPUT, FORWARD, OUTPUT 和 POSTROUTING 链路,允许附加到virtbr0设备的guest系统流量的进出。另外libvirt也会激活 ip_forward ,最佳的方式是添加以下配置到 /etc/sysctl.conf

net.ipv4.ip_forward = 1

这个值对应内核参数 /proc/sys/net/ipv4/ip_forward ,只要确保是 1 就可以转发虚拟机流量。

如果上述内核参数值不是1,则可以执行以下命令修订:

  echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
  echo "net.ipv4.conf.all.forwarding=1" >> /etc/sysctl.conf
  echo "net.ipv6.conf.all.forwarding=1" >> /etc/sysctl.conf
  sysctl -p

.. note::

   创建虚拟机参考 :ref:`create_vm`

virbr0设备DOWN排查

发现一个比较奇怪的问题,之前工作正常的NAT libvirt网络,突然不能正常通讯,虚拟机无法ping网关192.168.122.1,但是实际上default的libvirt网络是激活状态的:

virsh net-list

显示正常:

 Name      State    Autostart   Persistent
--------------------------------------------
 default   active   yes         yes

brctl show 也正常显示了虚拟网卡设备 virbr0-nic:

bridge name  bridge id               STP enabled     interfaces
br0          8000.7e33f1ea9ee3       no
virbr0               8000.7a5026bf337c       yes             virbr0-nic

但是,使用 ip addr 显示libvirt网络并未启动:

6: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
    link/ether 7a:50:26:bf:33:7c brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
       valid_lft forever preferred_lft forever
7: virbr0-nic: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel master virbr0 state DOWN group default qlen 1000
    link/ether 52:54:00:45:db:25 brd ff:ff:ff:ff:ff:ff

启动虚拟机之后检查,可以看到 virbr0 设备恢复了UP状态,但是绑定的``virbr0-nic``依然状态DOWN:

6: virbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 7a:50:26:bf:33:7c brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
       valid_lft forever preferred_lft forever
7: virbr0-nic: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel master virbr0 state DOWN group default qlen 1000
    link/ether 52:54:00:45:db:25 brd ff:ff:ff:ff:ff:ff
10: vnet0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master virbr0 state UNKNOWN group default qlen 1000
    link/ether 6e:5e:da:70:92:0b brd ff:ff:ff:ff:ff:ff
    inet6 fe80::fc54:ff:fe9f:98b9/64 scope link
       valid_lft forever preferred_lft forever

这让我很疑惑,特别是虚拟机网开 vnet0 状态 UNKNOWN 并且 virbr0-nic 状态始终为DOWN。

检查 brctl show 显示:

bridge name  bridge id               STP enabled     interfaces
br0          8000.7e33f1ea9ee3       no
virbr0       8000.7a5026bf337c       yes             virbr0-nic
                                                     vnet0

之前发现 virbr0 接口始终是DOWN状态,这可能是VM网络不通的原因。我关闭虚拟机,使用了 ip link set virtbr0 up 设置之后,再启动虚拟机,则这个接口会从DOWN自动转变成UP。则此时虚拟机能够通讯了。但是 virbr0-nic 始终是DOWN状态。

参考 How virbr0-nic is created? 解说,这个 virbr0-nic 是网络dummy设备。

使用以下命令可以检查虚拟机的虚拟网卡设备:

sudo virsh domiflist win10

输出显示:

 Interface   Type     Source   Model    MAC
-----------------------------------------------------------
 vnet0       bridge   virbr0   virtio   52:54:00:9f:98:b9