Libvirt --- networking

参考:https://wiki.libvirt.org/page/Networking


Networking

本文介绍了基于libvirt的应用的通用网络配置。可用于所有虚拟化,不管是Xen,KVM或者其他。

两种方式 "virtual network" , "shared physical device"。前者在所有的发布版本上都是一致的,封装好的,可以直接使用。后者需要自定义配置。


 1 NAT forwarding (即 "virtual networks")
  1.1 Host configuration
  1.2 Guest configuration
  1.3 Applying modifications to the network
   1.3.1 virsh net-update
   1.3.2 Arbitrary changes to the network
  1.4 Forwarding Incoming Connections
 2 Bridged networking (即 "shared physical device")
  2.1 Host configuration
   2.1.1 Fedora/RHEL Bridging
    2.1.1.1 Using NetworkManager directly
    2.1.1.2 Disabling NetworkManager (for older distros)
    2.1.1.3 Creating network initscripts
   2.1.2 Debian/Ubuntu Bridging
  2.2 Guest configuration
 3 PCI Passthrough of host network devices
  3.1 Assignment with
  3.2 Assignment with (SRIOV devices only)
  3.3 Assignment from a pool of SRIOV VFs in a libvirt definition
 4 Other networking docs/links


NAT forwarding (即 "virtual networks")

Host configuration

每个标准libvirt安装都提供自带的NAT基础连接到虚机。这也被称为'default virtual network'。你可以通过如下操作查看:

# virsh net-list --all
Name                 State      Autostart 
-----------------------------------------
default              active     yes

如果没有,那么如下的example XML config可以加载激活使用。

# virsh net-define /usr/share/libvirt/networks/default.xml
Network default defined from /usr/share/libvirt/networks/default.xml
# virsh net-autostart default
Network default marked as autostarted
# virsh net-start default
Network default started

当libvirt的default network运行,你可以看到一个独立的网桥设备。这个设备实际上没有任何物理接口,因为它使用NAT+转发 来连接外面的网络。不需要加任何接口。

# brctl show
bridge name bridge id       STP enabled interfaces
virbr0      8000.000000000000   yes

Libvirt会添加iptables rules到 INPUT, FORWARD, OUTPUT and POSTROUTING 规则链以允许guest的出入流量使用virbr0设备。它需要开启ip_forward。有些应用可能会禁用ip_forward,所以最好将如下配置添加到 /etc/sysctl.conf.

net.ipv4.ip_forward = 1

如果你在服务器上运行了dnsmasq,请参考 libvirtd and dnsmasq.

Guest configuration

如果host configuration完成了,guest就可以通过network name连到虚拟网络了。比如,如果要将一个guest连到'default'虚拟网络,你需要编辑该guest的domain configuration file:

virsh edit 

这里 是guest的名字或者uuid。将如下代码段添加到config文件:

  
     
     
  

MAC地址是可选的,如果没有会自动创建。

Applying modifications to the network

有时候,需要在运行的时候编辑网络。最常见的场景,添加新的 static MAC+IP映射虚拟网络的DHCP server。如果你通过"virsh net-edit"编辑网络,任何变更在网络被销毁重启前不会生效,这会导致所有的guest丢失网络连接直到它们的网卡接口重新连接。

virsh net-update
幸运的是,有很多网络变更操作可以通过"virsh net-update"立即生效,比如上面提到的在DHCP绑定MAC+IP。
比如, 添加一个名字为"default"的静态DHCP地址映射连到网络,MAC地址53:54:00:00:01映射到IP地址192.168.122.45,hostname为"bob",可以用如下命令:

    virsh net-update default add ip-dhcp-host \
          "" \
           --live --config

virsh net-update子命令除了 "add", 还有"delete" ,"modify" (for some items),"add-first", "add-last"。

如下是可以使用virsh net-update配置的网络配置项:

   ip-dhcp-host
   ip-dhcp-range (add/delete only, no modify)
   forward-interface (add/delete only)
   portgroup
   dns-host
   dns-txt
   dns-srv

注意,命令行的最后内容(并非"--live --config")应该是你想要add/modify/delete的XML片段。
比如,"virsh net-update default add forward-interface"后面跟的XML应该类似于""
(注意引号的使用 - 因为XML包含空格和字符转义,你必须用引号将真个XML片段包含起来,但这也意味着XML内只能使用单引号,或者反斜杠)

Arbitrary changes to the network

虽然很多配置变更可以使用 "virsh net-update",但是还有一些不可以。 在这种情况下,所有的guests只能断开网络知道网络重启。为了解决这个问题,一个可行的解决方案就是,在网络重启后,通过脚本自动挂载所有主机上的所有的接口。

脚本范例 (虽然很久之前用过,但是也有很多人报告失效了) is available here.

Forwarding Incoming Connections

默认,以 方式通过虚拟网络连接的guest对外可以访问任何网络。但是进来的连接只允许来自当前host,同一libvirt network下的其他guests,其他的都被iptables拒绝了。

如果你想把NAT虚拟网后的一个服务发布出去,你可以给qemu设置一个 libvirt 的 "hook" 脚本,来安装必要的iptables规则转发forward incoming connections to the host on any given port HP to port GP on the guest GNAME。

  1. 定义
    a) guest 的 name 为 "G" (定义在 libvirt domain XML中)
    b) guest 的IP地址 为 "I"
    c) 接受连接的guest port 为 "GP"
    d) 转发连接到guest的 host port 为 "HP"

(为使得guest's IP address 保持不变, 你可以给 guest OS 配置固定IP, 或者在 element内添加一个 element。详情请参考 the libvirt network XML documentation address section)

  1. 停止guest运行

  2. 创建文件 /etc/libvirt/hooks/qemu (或在一个已经存在的hook script后追加如下内容), 内容类似 (根据你的情况替换GNAME, IP, GP, and HP 变量):

如下是basic script,或者参考"advanced" 版本 here or here's a python script

#!/bin/bash

# IMPORTANT: Change the "VM NAME" string to match your actual VM Name.
# In order to create rules to other VMs, just duplicate the below block and configure
# it accordingly.
if [ "${1}" = "VM NAME" ]; then

   # Update the following variables to fit your setup
   GUEST_IP=
   GUEST_PORT=
   HOST_PORT=

   if [ "${2}" = "stopped" ] || [ "${2}" = "reconnect" ]; then
    /sbin/iptables -D FORWARD -o virbr0 -d  $GUEST_IP --dport $GUEST_PORT -j ACCEPT
    /sbin/iptables -t nat -D PREROUTING -p tcp --dport $HOST_PORT -j DNAT --to $GUEST_IP:$GUEST_PORT
   fi
   if [ "${2}" = "start" ] || [ "${2}" = "reconnect" ]; then
    /sbin/iptables -I FORWARD -o virbr0 -d  $GUEST_IP --dport $GUEST_PORT -j ACCEPT
    /sbin/iptables -t nat -I PREROUTING -p tcp --dport $HOST_PORT -j DNAT --to $GUEST_IP:$GUEST_PORT
   fi
fi
  1. chmod +x /etc/libvirt/hooks/qemu

  2. 重启 libvirtd service.

  3. 启动guest.

(注意: 这个办法是hack行为,在libvirt 0.9.13 版本前有瑕疵,如果libvirtd 在guest运行的时候重启了, 所有的支撑virtual network的标准Iptables rules会被重新加载, 导致变更了跟reject rule 有关的FORWARD rule 顺序, 那么在guest 停止和重启之前,这部分不工作了。 在libvirt-0.9.13 和 更新的版本,使用新"reconnect" hook , 在新版本的libvirt中,这个缺陷不存在了。 (不管怎么说, 这个 hook script 依然被认为是非常规操作---hack)。


Bridged networking (即 "shared physical device")

Host configuration

NAT连接使用方便,或者用于自动配置网络连接的情况。更高级的一些用户希望使用桥接方式,guest直接连到Lan网络。下面根据不同的发行版本或者OS版本,做了说明。

注意: 无线不可以使用桥接模式。
注意: 如果你配置桥接后,你发现你的网络连接挂了,不工作了,有可能是路由器/交换机屏蔽了“unauthorized switches”(比如,通过侦测BPDU包)。你需要配置主机网口工作为"switch"。

Fedora/RHEL Bridging
这部分展示如何通过标准网络初始化脚本和systemctl设置桥接。

  1. 使用NetworkManager 配置
    如果发行版有 NetworkManager, 原生支持桥接。文档如下:
  • 使用 nm-connection-editor UI: https://www.happyassassin.net/2014/07/23/bridged-networking-for-libvirt-with-networkmanager-2014-fedora-21/
  • 使用命令行: https://lukas.zapletalovi.com/2015/09/fedora-22-libvirt-with-bridge.html
  1. 不使用NetworkManager (for older distros)
    如果你的版本是2015年前的,NetworkManager 不支持桥接的设置,只能用传统的网络设置方式,并且不使用NetworkManager管理。( "NM_CONTROLLED=no" )
    彻底关闭NetworkManager也是可以的。
# chkconfig NetworkManager off
# chkconfig network on
# service NetworkManager stop
# service network start
  1. Creating network initscripts
    在 /etc/sysconfig/network-scripts 目录,创建两个配置文件。
    第一个文件 ifcfg-eth0定义了物理网络接口信息,并且指定归属网桥。
# cat > ifcfg-eth0 <

将HWADDR更改为你的网卡MAC地址。你也可以配置设备的MTU。比如: MTU=9000。

第二个文件 ifcfg-br0 定义桥接设备:

# cat > ifcfg-br0 <

WARNING: TYPE=Bridge 是区分大小写的。

配置完毕后,重启网络 (or reboot)

 # service network restart

最后,关闭桥接的网络过滤器netfilter

 # cat >> /etc/sysctl.conf <

为了性能和安全,建议这么配置。 See Fedora bug #512206.
或者,你可以配置iptables在桥接设备上转发所有:

# echo "-I FORWARD -m physdev --physdev-is-bridged -j ACCEPT" > /etc/sysconfig/iptables-forward-bridged
# lokkit --custom-rules=ipv4:filter:/etc/sysconfig/iptables-forward-bridged
# service libvirtd reload

现在,你有一个 "shared physical device"设备了, 可以用于guests直接接入LAN。

 # brctl show
 bridge name     bridge id               STP enabled     interfaces
 virbr0          8000.000000000000       yes
 br0             8000.000e0cb30550       yes             eth0

注意桥接是完全独立于 virbr0的,不要将物理设备绑定到virbr0。Virbr0仅用于NAT网络连接。

Debian/Ubuntu Bridging

Debian wiki bridging 的文档: https://wiki.debian.org/BridgeNetworkConnections

Guest configuration

要让虚拟机使用桥接,配置文件必须定义桥接。 Bridge to LAN
其实,可以通过bridge name 来配置连接。假设,shared physical device 的 bridge 被定义为 “br0”,guest XML可以配置如下:

 
    
    
       # try this if you experience problems with VLANs
 

mac address 是可选的,如果忽略将会自动生成。

使用 virsh edit 命令来编辑虚拟机配置文件

FAQ :http://wiki.libvirt.org/page/FAQ#Where_are_VM_config_files_stored.3F_How_do_I_edit_a_VM.27s_XML_config.3F


PCI Passthrough of host network devices

还可以将主机的PCI网络设备直接赋予guest。但是首先要保证主机支持 Intel VT-d or AMD IOMMU 扩展。
有两种方式:

Assignment with

将 generic PCI device 挂载到guest的常用方式:

libvirt PCI Device Assignment

Assignment with (SRIOV devices only)
SRIVO Single-root I/O virtualization,单根I/O虚拟化。SR-IOV 使一个单一的功能单元(比如,一个以太网端口)能看起来像多个独立的物理设备,即支持SR-IOV 功能的物理设备能被配置为多个功能单元。

SRIOV 网卡可以提供多路"Virtual Functions" (VF),可以分别挂载给使用PCI设备的guests,并且每个都等效一个物理网卡。这允许许多guests通过直连PCI设备获得高性能,但是只使用一个物理插槽。

VFs可以给以传统方式分配挂载给guest,但是这个模式会有问题(不像那些常见网络设备), SRIOV VF 网络设备没有永久唯一的MAC地址,而是每次OS重启会分配一个新的不同的随机MAC地址。结果就是,即使每次guest分配了同一个VF,只要是guest重启了就会获得一个新MAC地址,这就导致guest会将其识别为一个新的硬件设备,需要重新配置网络配置文件。

可以在把VF赋予guest前就配置好MAC地址。但是在 settings没有这个项目可以配置。 (因为 用于配置 generic PCI device, 它不能配置MAC地址。).
为了解决这个问题, libvirt-0.9.10 增加了一个新配置项 (documented here).。这个新接口类型运行在 的混杂模式 - libvirt 首先做网络设备配置初始化 (比如设置MAC地址, and/or 以802.1Qbh协商), 然后再把PCI设备赋予guest。

为了使用 , 你必须有SRIOV-capable 网卡, 主机支持Intel VT-d or AMD IOMMU 扩展,并且你必须知道你计划分配给VF的PCI地址 (see this document 怎么配置).

如上信息了解后,你可以编辑guest domain configuration来配置一个设备,参考如下:

 ...
 
   ...
   
     
       
...

(注意,如果没有提供mac地址,会自动创建就和其他类型的interface设备一样 。 另外, 如果你连到一个802.11Qgh硬件交换设备只能使用 element (802.11Qbg (即 "VEPA") switches 在这个模式不支持)).

当 guest 启动, 应该能看到一个已经配置好MAC地址的由物理设备提供的网络设备。 这个MAC地址在guest和host重启前保持不变。

SRIOV VFs 池的分配在libvirt 的定义
把PCI地址赋予guest配置有 两个严格限制:

  1. 任何时候,当guest启动时指定的VF必须可用,即管理员必须永久的分配每个VF到单个guest。 (或者每次当guest启动的时候,赋予guest一个当前未使用的VF's PCI address。)

  2. 如果guest被移动到其他host,那台host必须在相同的PCI总线位置有相同的硬件。 (或者,在启动前修改guest配置)

从 libvirt 0.10.0 开始,这些都可以通过以 device pool创建libvirt network的方式避免。Device pool 包含SR-IOV的所有的 VFs信息, 然后配置guest调用这个网络;每当guest启动, 一个单独的 VF会从池内取出分配给guest;当guest关闭, VF将被返还到池内以供其他guest使用

如下是一个网络配置范例,一个定义在host上名为"eth3"的,SR-IOV设备VFs池。

 
   passthrough
   
     
   
 

要使用这个网络,将如上配置到 /tmp/passthrough.xml (使用你自己的SR-IOV device's PF替换 "eth3" ), 然后执行如下命令:

  virsh net-define /tmp/passthrough.xml
  virsh net-autostart passthrough
  virsh net-start passthrough.

虽然只有一个设备被显示出来, libvirt 会自动获得一个首次使用如下interface定义的guest的PF的所有VFs 清单 :

  
    
  

你可以在启动第一个使用该网络的guest后,执行 "virsh net-dumpxml passthrough"命令来确认; 类似如下输出:

 
   passthrough
   a6b49429-d353-d7ad-3185-4451cc786437
   
     
     

Other networking docs/links

  • David Lutterkort's guide. 注意, 'peth0' (physical) 和 'eth0' (bridge) 在 Fedora 9 不再生效了。由 'eth0' (physical) 和 'br0' (bridge) 替代。
  • Anthony Liguori's guide . Debian的 'shared physical devices'
  • manual KVM networking - 不使用libvirt加载guests的情况
  • Ubuntu libvirt guide -网桥配置节选

你可能感兴趣的:(Libvirt --- networking)