KVM虚拟化:(十)网络配置简介

admin 2022年11月24日 1,385次浏览

1、QEMU支持的网络模式

  • 基于网桥(bridge)的虚拟网络

  • 基于NAT的虚拟网络

  • QEMU内置的用户模式网络

  • 直接分配网络设备从而直接接入物理网络(包括VT-d和SR-IOV)

在 qemu 命令行中,对客户机网络的配置通常用 -net 参数进行配置,如果没有设置任何的 -net 参数,则默认使用 -net nic-net user 参数,进而使用完全基于 QEMU 内部实现的用户模式下的网络协议栈。推荐用 -device + -netdev 组合的方式进行网络配置

QEMU 提供了对一系列主流和兼容性良好的网卡的模拟,通过 net nic,model=? 参数可以查询到当前的QEMU工具实现了哪些网卡的模拟

[root@kvm ~]# qemu-system-x86_64 -net nic,model=?
Supported NIC models:
e1000、e1000-82544gc、e1000-82545em、e1000e、i82550、i82551、i82557a、i82557b、i82557c、i82558a、i82558b、i82559a、i82559b、i82559c、i82559er、i82562、i82801、ne2k_pci、pcnet、rtl8139、tulip、virtio-net-pci、virtio-net-pci-non-transitional、virtio-net-pci-transitional、vmxnet3

e1000 是提供 Intel e1000 系列的网卡模拟,如果不显式指定,QEMU 默认模拟 Intel e1000 系列的虚拟网卡。而 virtio 类型是 QEMU 对半虚拟化 I/O(virtio)驱动的支持

qemu 命令行在不加任何网络相关的参数启动客户机后,在客户机中可以看到它有一个默认的 e1000 系列的网卡,由于没有进行更多的网络配置,这个模拟的网卡虽然在客户机中可见,但是它使用的是用户模式的网络,其功能非常有限

  • -net 参数的使用

    -net nic[,macaddr=mac][,model=type][,name=str][,addr=str][,vectors=v]
    
    • -net nic:必需参数,表明这是一个网卡的配置
    • macaddr:设置网卡的 MAC 地址,默认根据宿主机中网卡的地址来分配。若局域网中客户机太多,建议自己设置 MAC 地址,以防止 MAC 地址冲突
    • model:设置模拟的网卡的类型,默认为 e1000
    • name:为网卡设置一个易读的名称,该名称仅在 QEMU monitor 中可能用到
    • addr:设置网卡在客户机中的 PCI 设备地址
    • vectors:设置该网卡设备的 MSI-X 向量的数量,该选项仅对使用 virtio 驱动的网卡有效。设置为 vectors=0 则关闭 virtio 网卡的 MSI-X 中断方式

在宿主机中用如下命令行启动一个客户机

[root@kvm qemu]# qemu-system-x86_64 -m 1024 /img_dir/centos7.qocw2 -net nic,macaddr=52:54:00:12:34:22,model=e1000,addr=08 -net user -monitor stdio

2、网桥模式

在 QEMU/KVM 的网络使用中,网桥(bridge)模式可以让客户机和宿主机共享一个物理网络设备连接网络,客户机有自己的独立 IP 地址,可以直接连接与宿主机一模一样的网络,客户机可以访问外部网络,外部网络也可以直接访问客户机。也就是说宿主机只有一个网卡设备,使用 bridge 模式也可让多个客户机与宿主机共享网络设备

在 qemu 命令行中,配置 bridge 模式网络参数格式

-netdev tap,id=str[,fd=h][,fds=x:y:...:z][,ifname=name][,script=file][,downscript=dfile] [,br=bridge][,helper=helper]

参数说明

  • tap:使用 TAP 虚拟网络设备(2层设备)

  • id:网桥名称

  • fd:连接到已经打开的 TAP 接口

  • fds:连接到已经打开的支持多队列的 TAP 接口

  • ifname:设置在宿主机中添加的 TAP 虚拟设备的名称

  • script:设置宿主机在启动客户机时自动执行的网络配置脚本。如果不指定,其默认值为:/etc/qemu-ifup;如果不需要执行脚本,则设置为:script=no

  • downscript:设置宿主机在客户机关闭时自动执行的网络配置脚本。如果不设置,其默认值为:/etc/qemu-ifdown;若客户机关闭时宿主机不需要执行脚本,则设置为:downscript=no

  • helper:使用网络助手 helper 配置

2.1、配置网桥

该文档是基于 centos7 环境编写,如果是在 RHEL9 或者 rocky Linux9中创建网桥,请参见:RHEL9 配置网络桥接

2.1.1、安装软件包

要采用 bridge 模式的网络配置,首先需要安装 bridge-utils 软件包,它提供 brctl 工具,用于配置网桥

[root@kvm ~]# yum install bridge-utils -y

2.1.2、查看tun模块和bridge模块是否加载

[root@kvm ~]# lsmod | grep tun
tun                    65536  1

[root@kvm ~]# lsmod | grep bridge
bridge                327680  0
stp                    16384  1 bridge
llc                    16384  2 bridge,stp

2.1.3、brctl常用命令

brctl 用于设置、维护和检查 linux 内核中的网桥配置

  • 新建网桥

    brctl addbr <name>
    
  • 删除网桥

    brctl delbr <name>
    
  • 查看网桥信息

    brctl delbr <name>
    
  • 创建桥接

    使接口 <ifname> 成为网桥 < brname > 的端口,并将< ifname >上收到的所有帧都将被发往网桥。此外,在 < brname > 上发送帧时,< ifname > 将被视为潜在的输出接口

    brctl addif <brname> <ifname>
    

    brname:网桥名称

    ifname:网络接口

  • 删除桥接

    使接口 < ifname > 与网桥 < brname > 分离

    brctl delif <brname> <ifname >
    
  • 设置网桥转发延迟

     brctl setfd <bridge> <time>
    

2.1.4、检查/dev/net/tun的权限

[root@kvm ~]# ls -la /dev/net/tun
crw-rw-rw-. 1 root root 10, 200 11月 22 15:16 /dev/net/tun

2.1.5、创建bridge

网络桥接配置可参考:官方文档

建立一个 bridge,并将其绑定到一个可以正常工作的网络接口上,同时让 bridge 成为连接本机与外部网络的接口

  • 创建bridge

    [root@kvm ~]# brctl addbr virbr0
    
  • 创建virbr0配置文件

    [root@kvm ~]# vim  /etc/sysconfig/network-scripts/ifcfg-virbr0
    DEVICE=virbr0
    STP=yes
    TYPE=Bridge
    BOOTPROTO=none
    NAME=virbr0
    ONBOOT=yes
    
    IPADDR=192.168.1.10
    PREFIX=24
    GATEWAY=192.168.1.1
    DNS1=61.139.2.29
    DNS2=114.114.114.114
    
  • 修改需要绑定到网桥的物理接口的配置文件

    [root@kvm ~]# vim /etc/sysconfig/network-scripts/ifcfg-enp5s0
    TYPE=Ethernet
    BOOTPROTO=none
    DEFROUTE=no
    IPV4_FAILURE_FATAL=no
    NAME=enp5s0
    UUID=88fda120-e410-451b-aabb-1234567890ab
    DEVICE=enp5s0
    ONBOOT=yes
    # 将本网卡桥接到virbr0上
    BRIDGE=virbr0    
    
  • 查看网桥信息

    [root@kvm ~]# brctl show
    bridge name     bridge id               STP enabled     interfaces
    virbr0          8000.000000000000       yes
    
  • 将virbr0绑定到物理网卡

    [root@kvm ~]# brctl addif virbr0 enp5s0
    
    [root@kvm ~]# brctl show
    bridge name     bridge id               STP enabled     interfaces
    virbr0          8000.22135c0309fc       yes             enp5s0
    
  • 重启网络服务

    [root@kvm ~]# systemctl restart network
    
  • 查看网络配置

    [root@kvm ~]# nmcli
    virbr0: 已连接 to virbr0
            "virbr0"
            bridge, 22:13:5C:01:23:AB, 软件, mtu 1500
            ip4 默认
            inet4 192.168.1.10/24
            route4 192.168.1.0/24
            route4 0.0.0.0/0
            inet6 fe80::2013:1234:5678:123/64
            route6 fe80::/64
    
    enp5s0: 已连接 to enp5s0
            "Realtek RTL8111/8168/8411"
            ethernet (r8169), 22:13:11:11:11:11, 硬件, mtu 1500
            主连接 virbr0
    
    DNS configuration:
            servers: 61.139.2.29 114.114.114.114
            interface: virbr0
    

需要注意的是,作为网桥接口的附属(slave),enp5s0 接口是没有自己的 IP 地址的,网桥寄生在它身上(与它的MAC地址相同)与外界通讯

图:创建virbr0后接口示意图

2.1.6、准备qemu-ifup和qemu-ifdown脚本

在客户机启动网络前执行的脚本是由 script 选项配置的(默认为/etc/qemu-ifup)。该脚本的内容就是将 QEMU自动创建的 TAP 设备绑定到上一步创建好的网桥上

[root@kvm ~]# vim /etc/qemu-ifup
#!/usr/bin/bash
switch=$(brctl show| sed -n 2p |awk '{print $1}')
/sbin/ifconfig $1 0.0.0.0 up
/usr/sbin/brctl addif ${switch} $1

[root@kvm ~]# vim /etc/qemu-ifdown
#!/usr/bin/bash
switch=$(brctl show| sed -n 2p |awk '{print $1}')
if [ -n "$1" ]; then
tunctl -d $1
brctl delif ${switch} $1
ip link set $1 down
exit 0
else
echo "Error: no interface specified"
exit 1
fi

[root@kvm ~]# chmod +x /etc/qemu-ifup
[root@kvm ~]# chmod +x /etc/qemu-ifdown

$1 是 QEMU 调用脚本时传入的参数,它是 QEMU 为客户机创建的 TAP 设备名称。由于 QEMU 在客户机关闭时会解除 TAP 设备的 bridge 绑定,也会自动删除已不再使用的 TAP 设备,所以 qemu-ifdown 这个脚本不是必需的,最好设置为 downscript=no

2.2、使用bridge网络

2.2.1、通过客户机配置文件使用

修改配置文件时,不建议直接修改源文件,而是使用 virsh edit 客户机名称 的方式修改,该命令等同于 vim /etc/libvirt/qemu/客户机名称.xml,然后增加了配置验证功能

[root@kvm ~]# virsh edit centos7
<!-- 修改网络方式为bridge -->
<interface type='bridge'>
      <mac address='52:54:00:32:7d:f6'/>
      <!-- 使用的网络配置 -->
      <source bridge='virbr0'/>
      <!-- 虚拟的网卡 -->
      <model type='rtl8139'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/></interface>

2.2.2、在virt-manager中使用

在 virt-manager 中修改配置后,最终还是将配置同步到 /etc/libvirt/qemu/客户机名称.xml 配置文件中

2.2.3、命令方式使用

[root@kvm ~]# qemu-system-x86_64 /img_dir/centos7.qocw2 -enable-kvm -smp 4 -m 8G -net nic -net tap,script=/etc/qemu-ifup

# 查看客户机网络
[root@localhost ~]# nmcli
ens3: 已连接 to ens3
        "Intel 82540EM"
        ethernet (e1000), 52:54:00:12:34:56, 硬件, mtu 1500
        ip4 默认
        inet4 192.168.1.111/24
        route4 0.0.0.0/0
        route4 192.168.1.0/24

DNS configuration:
        servers: 61.139.2.69 114.114.114.114
        interface: ens3

图:启动客户机后网桥拓扑示意图

3、NAT模式

NAT(网络地址转换)属于广域网接入技术的一种,它将内网地址转化为外网的合法 IP 地址,它被广泛应用于各种类型的 Internet 接入方式和各种类型的网络之中

在 KVM 中配置客户机的 NAT 网络方式,需要在宿主机中运行一个 DHCP 服务器给宿主机分配 NAT 内网的 IP 地址,可以使用 dnsmasq 工具来实现

3.1、配置NAT网络

  • 安装必要的软件包

    要使用 NAT 网络,需要安装 bridge-utils、iptables 和 dnsmasq 等软件包。其中 bridge-utils 包含管理 bridge 的工具 brctl,iptables 是对内核网络协议栈中 IPv4 包的过滤工具和 NAT 管理工具,dnsmasq 是一个轻量级的 DHCP 和 DNS 服务器软件

    [root@kvm ~]#  rpm -q bridge-utils iptables  dnsmasq
    bridge-utils-1.5-9.el7.x86_64
    iptables-1.4.21-35.el7.x86_64
    dnsmasq-2.76-17.el7_9.3.x86_64
    

3.1.1、使用脚本方式启动

  • 创建相关脚本

    准备一个为客户机建立 NAT 用的 qemu-ifup 脚本及关闭网络用的 qemu-ifdown 脚本,这两个脚本中的 $1 就是在客户机中使用的网络接口在宿主机中的虚拟网络名称(如tap0、tap1等)

    客户机启动时调用的 qemu-ifup-NAT 脚本的主要功能是:建立 bridge,设置 bridge 的内网 IP,并且将客户机的网络接口与其绑定,然后打开系统中网络 IP 包转发的功能,设置 iptables 的 NAT 规则,最后启动 dnsmasq 作为一个简单的 DHCP 服务器

    [root@kvm ~]# vim /etc/qemu-ifup-NAT
    #!/bin/bash
    # 设置 bridge 名称
    BRIDGE=natnet
    # 设置网络信息
    NETWORK=192.168.137.0
    NETMASK=255.255.255.0
    GATEWAY=192.168.137.1
    DHCPRANGE=192.168.137.100,192.168.137.200
    # 启用PXE支持的可选参数
    TFTPROOT=
    BOOTP=
    
    function check_bridge()
    {
            if brctl show | grep "^$BRIDGE" &> /dev/null; then
                    return 1
            else
                    return 0
            fi
    }
    
    function create_bridge()
    {
            brctl addbr "$BRIDGE"
            brctl stp "$BRIDGE" on
            brctl setfd "$BRIDGE" 0
            ifconfig "$BRIDGE" "$GATEWAY" netmask "$NETMASK" up
    }
    
    function enable_ip_forward()
    {
            echo 1 > /proc/sys/net/ipv4/ip_forward
    }
    
    function add_filter_rules()
    {
            iptables -t nat -A POSTROUTING -s "$NETWORK"/"$NETMASK" \
                    ! -d "$NETWORK"/"$NETMASK" -j MASQUERADE
    }
    
    function start_dnsmasq()
    {
    # 禁止重复运行dnsmasq
            ps -ef | grep "dnsmasq" | grep -v "grep" &> /dev/null
            if [ $? -eq 0 ]; then
                    echo "dnsmasq 已经在运行"
                    return 1
            fi
            dnsmasq \
                    --strict-order \
                    --except-interface=lo \
                    --interface=$BRIDGE \
                    --listen-address=$GATEWAY \
                    --bind-interfaces \
                    --dhcp-range=$DHCPRANGE \
                    --conf-file="" \
                    --pid-file=/var/run/qemu-dhcp-$BRIDGE.pid \
                    --dhcp-leasefile=/var/run/qemu-dhcp-$BRIDGE.leases \
                    --dhcp-no-override \
                    ${TFTPROOT:+"--enable-tftp"} \
                    ${TFTPROOT:+"--tftp-root=$TFTPROOT"} \
                    ${BOOTP:+"--dhcp-boot=$BOOTP"}
    }
    
    function setup_bridge_nat()
    {
            check_bridge "$BRIDGE"
            if [ $? -eq 0 ]; then
                    create_bridge
            fi
            enable_ip_forward
            add_filter_rules "$BRIDGE"
            start_dnsmasq "$BRIDGE"
    }
    
    # 安装前需要检查$1参数
    if [ -n "$1" ]; then
            setup_bridge_nat
            ifconfig "$1" 0.0.0.0 up
            brctl addif "$BRIDGE" "$1"
            exit 0
    else
            echo "发现错误:没有指定接口"
            exit 1
    fi
    
    [root@kvm ~]# chmod +x /etc/qemu-ifup-NAT
    

    关闭客户机时调用的网络脚本 qemu-ifdown-NAT 的主要功能是要完成解除 bridge 绑定、删除 bridge 和清空 iptalbes 的 NAT 规则

    [root@kvm ~]# vim /etc/qemu-ifdown-NAT
    [root@kvm ~]# cat /etc/qemu-ifdown-NAT
    #!/bin/bash
    BRIDGE=natnet
    if [ -n "$1" ]; then
            echo "正在断开接口 $1"
            ip link set $1 down
            brctl delif "$BRIDGE" $1
            tap=`brctl show | grep natnet | awk '{print $4}'`
            if [[ $tap != tap* ]];then
                ip link set "$BRIDGE" down
                brctl delbr "$BRIDGE"
                iptables -t nat -F
                kill `ps aux | grep dnsmasq | grep -v grep | awk '{print $2}'`
                echo "断开接口 $1 成功"
                echo "网桥 $BRIDGE 卸载成功"
                echo "dnsmasq 服务停止成功"
                exit 0
            else
                echo "断开接口 $1 成功"
                exit 0
            fi
    else
            echo "删除错误:未指定接口"
            exit 1
    fi
    
    
    [root@kvm ~]# chmod +x /etc/qemu-ifdown-NAT
    
  • 使用以上两个脚本启动客户机

    [root@kvm ~]# qemu-system-x86_64 -enable-kvm -smp 2 -m 4G -net nic,netdev=nic0 -netdev tap,id=nic0,script=/etc/qemu-ifup-NAT,downscript=/etc/qemu-ifdown-NAT /img_dir/centos7.qocw2
    
  • 查看网络信息

    [root@kvm ~]# brctl show
    bridge name     bridge id               STP enabled     interfaces
    nat_net         8000.46e1f431817e       yes             tap0
    virbr0          8000.22135c0309fc       yes             enp5s0
    
  • 配置端口转发

    [root@kvm ~]# iptables -t nat -A PREROUTING -p tcp -d 192.168.1.10 --dport 2222 -j DNAT --to 192.168.0.157:22
    

3.1.2、使用网络配置文件方式启动

  • 修改(创建)NAT网络配置文件

    NAT 的网络配置文件默认存放路径为 /etc/libvirt/qemu/networks/ ,默认的 NAT 配置文件名称为 default.xml,我们可以修改原有的配置文件,也可以在该目录下重新创建一个新的网络配置文件

    [root@kvm ~]# virsh net-edit --network default
    <network>
      <!-- 配置文件名称 -->
      <name>default</name>
      <uuid>8c1240ab-bf0e-44ae-bf8d-87c554b49e29</uuid>
      <!-- 网络模式,这里使用NAT模式-->
      <forward mode='nat'/>
      <!-- 配置网络名称、是否启用STP、转发延迟 -->
      <bridge name='nat_net' stp='on' delay='1'/>
      <mac address='52:54:00:f2:80:c2'/>
      <!-- 配置网络信息 -->
      <ip address='192.168.137.1' netmask='255.255.255.0'>
        <dhcp>
          <!-- 配置DHCP地址池-->
          <range start='192.168.137.2' end='192.168.137.254'/>
        </dhcp>
      </ip>
    </network>
    
  • 激活NAT网络

    [root@kvm ~]# virsh net-start --network default
    

3.2、使用NAT网络

3.2.1、通过客户机配置文件使用

[root@kvm ~]# vim /etc/libvirt/qemu/centos7.xml
<!-- 修改网络方式为NAT -->
<interface type='network'>
      <mac address='52:54:00:32:7d:f6'/>
      <!-- 使用的网络配置 -->
      <source network='default'/>
      <!-- 虚拟的网卡 -->
      <model type='rtl8139'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>

3.2.2、在virt-manager中使用

4、用户模式

在没有任何 -net 参数时,QEMU 默认使用的是 -net nic-net user 的参数,提供了一种用户模式的网络模拟。使用用户模式的网络的客户机可以连通宿主机及外部的网络。用户模式网络完全是由 QEMU 自身实现的,不依赖于其他的工具,而且不需要 root 用户权限。QEMU 使用 Slirp 实现了一整套 CP/IP 协议栈,并且使用这个协议栈实现了一套虚拟的 NAT 网络

  • 优点

    由于其使用简单、独立性好、不需 root 权限、客户机网络隔离性好等优势,用户模式网络是 QEMU 的默认网络配置

  • 缺点

    • 由于其在 QEMU 内部实现所有网络协议栈,因此其性能较差

    • 不支持部分网络功能(如ICMP),所以不能在客户机中使用 ping 命令测试外网连通性

    • 不能从宿主机或外部网络直接访问客户机

4.1、配置用户模式

  • 语法

    -netdev user,id=str[,ipv4=on|off][,net=addr[/mask]][,host=addr] [,restrict=on|off][,hostname=host][,dhcpstart=addr] [,dns=addr][,dnssearch=domain][,domainname=domain][,hostfwd=rule] ...
    
  • 常用参数解释

    • id:网桥名称
    • ipv4:使用ipv4网络
    • net:网络地址
    • host:配置主机的网络地址
    • restrict:如果将此选项设置为 on,则客户机将会被隔离,客户机不能与宿主机通信,其 IP 数据包也不能通过宿主机而路由到外部网络中。默认值为 no,不会隔离客户机
    • hostname:设置在内置的DHCP服务器中保存的客户机主机名
    • dhcpstart:设置能够分配给客户机的第1个 IP
    • dns:指定虚拟 DNS 的地址,这个地址必须与宿主机地址不相同,其默认值是网络中的第3个 IP 地址
    • dnssearch:内置的 DHCP server 在分配IP给客户机的时候,会附带 DNS 域的信息
    • domainname:DNS 域名
    • hostfwd:端口转发,其格式为 hostfwd=[tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport

4.2、使用用户模式网络

  • 在命令行中使用

    [root@kvm ~]# qemu-system-x86_64 -smp 4 -m 4G -enable-kvm /img_dir/centos7.qocw2 -device e1000,netdev=usernet0 -netdev user,id=usernet0,net=192.168.0.0/24,host=192.168.0.10,hostfwd=tcp::2201-:22
    
  • 测试外网访问客户机

    [root@centos ~]# ssh root@192.168.10.100 -p 2201
    root@192.168.10.100's password:
    Last login: Thu Nov 24 13:19:58 2022
    [root@localhost ~]# nmcli
    ens3: 已连接 to ens3
            "Intel 82540EM"
            ethernet (e1000), 52:54:00:12:34:56, 硬件, mtu 1500
            ip4 默认
            inet4 192.168.0.15/24
            route4 0.0.0.0/0
            route4 192.168.0.0/24
    
    DNS configuration:
            servers: 192.168.0.3
            interface: ens3
    
  • 测试访问外网

    [root@localhost ~]# ping www.baidu.com
    PING www.a.shifen.com (14.215.177.38) 56(84) bytes of data.
    64 bytes from 14.215.177.38 (14.215.177.38): icmp_seq=1 ttl=255 time=229 ms
    64 bytes from 14.215.177.38 (14.215.177.38): icmp_seq=2 ttl=255 time=38.1 ms
    64 bytes from 14.215.177.38 (14.215.177.38): icmp_seq=3 ttl=255 time=368 ms
    
    --- www.a.shifen.com ping statistics ---
    3 packets transmitted, 3 received, 0% packet loss, time 2003ms
    rtt min/avg/max/mdev = 38.108/212.028/368.314/135.382 ms