在KVM中,虚拟机可以通过虚拟交换机连接到虚拟网络,或者通过驱动直接连接到宿主机网络,亦或者是二者的结合。
KVM Network

KVM NetworkKVM Network

目录

  1. 虚拟网络
    1. NAT模式
      1. 创建网络
      2. 网络设备
      3. iptables规则
      4. 路由规则
      5. 创建虚拟机
      6. 网络测试
    2. Routed模式
      1. 创建网络
      2. 网络设备
      3. iptables规则
      4. 路由规则
      5. 创建虚拟机
      6. 网络测试
    3. Isolated模式
    4. Bridged模式
      1. 创建网络

虚拟网络

KVM使用虚拟交换机实现虚拟网络。虚拟交换机是一个在宿主机上运行的软件组件,虚拟机可以接入到该组件中,并引导其流量通过该组件。连接到特定虚拟交换机的虚拟机之间的流量保持在相关联的虚拟网络的范围内。从虚拟机的角度来看,虚拟网络连接与普通物理网络连接相同。

在宿主机上,虚拟交换机显示为网络接口,通常称为virbr0。

1
2
3
4
5
ip a show virbr0
51: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
link/ether 52:54:00:04:a9:99 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

在默认模式(NAT模式)下,该网络接口明确没有添加任何物理接口,因为它使用NAT转发连接到外部。这可以通过在宿主机上运行brctl show来证明。路由地址默认为192.168.122.1,到物理网络接口的路由在虚拟主机网络层中完成。libvirt将添加iptables规则,以允许进出virbr0接口的流量。它还将启用路由所需的IP转发。

默认的虚拟网络配置可以通过virsh net-dumpxml default显示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<network>
<name>default</name>
<uuid>40b7c068-9791-4466-bfa6-77ca0bedb2e4</uuid>
<forward mode='nat'>
<nat>
<port start='1024' end='65535'/>
</nat>
</forward>
<bridge name='virbr0' stp='on' delay='0'/>
<mac address='52:54:00:04:a9:99'/>
<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>

虚拟交换机由libvirtd守护进程通过dnsmasq进程启动和管理。为每个虚拟交换机及其关联的虚拟网络启动dnsmasq的新实例,仅该特定网络中的虚拟机可以访问。dnsmasq充当虚拟网络的DNS和DHCP服务器。此类dnsmasq实例的配置文件为/var/lib/libvirt/dnsmasq/.conf。默认情况下,只有一个“默认”虚拟网络,其dnsmasq配置文件为var/lib/libvirt/dnsmasq/default.conf。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
##WARNING:  THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE
##OVERWRITTEN AND LOST. Changes to this configuration should be made using:
## virsh net-edit default
## or other application using the libvirt API.
##
## dnsmasq conf file created by libvirt
strict-order
pid-file=/run/libvirt/network/default.pid
except-interface=lo
bind-dynamic
interface=virbr0
dhcp-range=192.168.122.2,192.168.122.254,255.255.255.0
dhcp-no-override
dhcp-authoritative
dhcp-lease-max=253
dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile
addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts

可以使用virsh net-edit编辑网络配置文件。

1
virsh net-edit <virtual-network-name>

如果启动服务后virbr0网桥不存在,可以执行下面的命令。

1
2
virsh net-autostart default
virsh net-start default

虚拟网络有4种模式,分别是NAT模式(默认)、Isolated模式(Host-only模式/隔离模式)、Routed模式(路由模式)和Bridged模式(桥接模式)。

NAT模式

NAT是默认的虚拟网络模式。在NAT模式中,使虚拟机借助NAT(网络地址转换)功能,通过宿主机器所在的网络来访问公网。虚拟机的网卡和物理网卡的网络,不在同一个网络,虚拟机的网卡,提供的是一个虚拟网络。
Network NAT
{ image fancybox center images/network_nat.png ‘Network NAT’}

NAT模式会将源地址转化为宿主机的物理网卡地址,所以局域网中的其他主机是无法访问虚拟机的,而宿主机可以访问虚拟机,虚拟机可以访问局域网内的所有主机。

创建网络

首先确保宿主机的IP转发已经打开。

1
2
3
cat /proc/sys/net/ipv4/ip_forward
# IP转发打开,值为1。
1

如果没有打开,利用下面的命令打开IP地址转发。

1
sudo sysctl -w net.ipv4.ip_forward=1

查看宿主机的网络设备,eno1。

1
2
3
4
5
6
7
ip a
eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:e0:70:e8:fd:b7 brd ff:ff:ff:ff:ff:ff
inet 10.12.17.200/24 brd 10.12.17.255 scope global dynamic noprefixroute eno1
valid_lft 26998sec preferred_lft 26998sec
inet6 fe80::1f78:1d6:7d71:8430/64 scope link noprefixroute
valid_lft forever preferred_lft forever

创建一个NAT模式的网络,下面是网络的详细配置文件nat-network.xml。

1
2
3
4
5
6
7
8
9
10
11
<network>
<name>nat-network</name>
<forward mode='nat' dev='eno1'/>
<bridge name='virbr-nat' stp='on' delay='2'/>
<ip address='192.168.10.1' netmask='255.255.255.0'>
<dhcp>
<range start='192.168.10.2' end='192.168.10.254'/>
<host name='myhost' ip='192.168.10.10'/>
</dhcp>
</ip>
</network>

先解读一下nat-network.xml的配置文件。

第三行,forward表明虚拟网络将连接到物理LAN。forward的mode(模式)包括nat(默认)、route、open、bridge、private、vepa、passthrough
和hostdev,其中nat表示连接到此网络的虚拟机和物理网络之间的所有流量将通过宿主机的IP路由堆栈转发到物理网络,之后虚拟机的IP地址被转换为宿主机的IP地址(NAT,网络地址转换)。另外Isolated模式(Host-only模式/隔离模式)下的网络配置文件中没有forward这一项。forward的dev属性使防火墙规则将仅限制转发加到指定的设备上,不设置dev属性,会默认转发到任意设备上。

第四行,bridge用于指定构建虚拟网络的网桥设备,虚拟机接入这个网桥设备用于互相通信,这个网桥设备也可以接入到物理LAN中。当forward的mode(模式)为:nat、route或者open时,如果bridge的name未指定,会自动随机生成一个网桥的名称。对于nat、route、open和isolated类型的网络,建议网桥设备的名称以virbr作为前缀。属性stp指定Spanning Tree Protocol(生成树协议,按照树的结构来构造网络拓扑,消除网络中的环路,避免由于环路的存在而造成广播风暴问题。)是on或off(默认on)。属性delay设置网桥桥的转发延迟值,单位是秒(默认为0)。

第五至十行,其中ip用于定义虚拟网络的IP地址包括IPv4和IPv6。dhcp用于定义虚拟网络的DHCP服务,其中range表示DHCP服务可分配IP的范围,host可以预定义主机的名称和IP地址以及mac地址。

然后利用libvirt的命令创建虚拟网络nat-network。

1
2
3
4
5
6
7
8
9
10
virsh net-define nat-network.xml
virsh net-start nat-network
virsh net-autostart nat-network

# 查看网络列表
virsh net-list --all
名称 状态 自动开始 持久
-----------------------------------------
default 不活跃 否 是
nat-network 活动 是 是

网络设备

创建好nat-network后,系统会自动创建一个网络设备virbr-nat,且它的IP地址是192.168.10.1/24。

1
2
3
4
virbr-nat: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
link/ether 52:54:00:e2:52:bd brd ff:ff:ff:ff:ff:ff
inet 192.168.10.1/24 brd 192.168.10.255 scope global virbr-nat
valid_lft forever preferred_lft forever

利用brctl命令查看网桥设备。

1
2
3
brctl show
bridge name bridge id STP enabled interfaces
virbr-nat 8000.5254004dcf1b yes

brctl命令可以通过yum install -y bridge-utils来安装。

iptables规则

NAT模式底层依靠iptables实现,在创建nat-network之前,filter表的规则如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
iptables -vnL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
22789 4974K LIBVIRT_INP all -- * * 0.0.0.0/0 0.0.0.0/0

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 LIBVIRT_FWX all -- * * 0.0.0.0/0 0.0.0.0/0
0 0 LIBVIRT_FWI all -- * * 0.0.0.0/0 0.0.0.0/0
0 0 LIBVIRT_FWO all -- * * 0.0.0.0/0 0.0.0.0/0

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
21989 3472K LIBVIRT_OUT all -- * * 0.0.0.0/0 0.0.0.0/0

Chain LIBVIRT_INP (1 references)
pkts bytes target prot opt in out source destination

Chain LIBVIRT_OUT (1 references)
pkts bytes target prot opt in out source destination

Chain LIBVIRT_FWO (1 references)
pkts bytes target prot opt in out source destination

Chain LIBVIRT_FWI (1 references)
pkts bytes target prot opt in out source destination

Chain LIBVIRT_FWX (1 references)
pkts bytes target prot opt in out source destination

nat表的规则如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
iptables -t nat -vnL
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination

Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
2082 143K LIBVIRT_PRT all -- * * 0.0.0.0/0 0.0.0.0/0

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination

Chain LIBVIRT_PRT (1 references)
pkts bytes target prot opt in out source destination

创建完虚拟网络nat-network后,先看filter表的规则。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
iptables -vnL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
32440 10M LIBVIRT_INP all -- * * 0.0.0.0/0 0.0.0.0/0

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 LIBVIRT_FWX all -- * * 0.0.0.0/0 0.0.0.0/0
0 0 LIBVIRT_FWI all -- * * 0.0.0.0/0 0.0.0.0/0
0 0 LIBVIRT_FWO all -- * * 0.0.0.0/0 0.0.0.0/0

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
30617 4478K LIBVIRT_OUT all -- * * 0.0.0.0/0 0.0.0.0/0

Chain LIBVIRT_INP (1 references)
pkts bytes target prot opt in out source destination
0 0 ACCEPT udp -- virbr-nat * 0.0.0.0/0 0.0.0.0/0 udp dpt:53
0 0 ACCEPT tcp -- virbr-nat * 0.0.0.0/0 0.0.0.0/0 tcp dpt:53
0 0 ACCEPT udp -- virbr-nat * 0.0.0.0/0 0.0.0.0/0 udp dpt:67
0 0 ACCEPT tcp -- virbr-nat * 0.0.0.0/0 0.0.0.0/0 tcp dpt:67

Chain LIBVIRT_OUT (1 references)
pkts bytes target prot opt in out source destination
0 0 ACCEPT udp -- * virbr-nat 0.0.0.0/0 0.0.0.0/0 udp dpt:53
0 0 ACCEPT tcp -- * virbr-nat 0.0.0.0/0 0.0.0.0/0 tcp dpt:53
0 0 ACCEPT udp -- * virbr-nat 0.0.0.0/0 0.0.0.0/0 udp dpt:68
0 0 ACCEPT tcp -- * virbr-nat 0.0.0.0/0 0.0.0.0/0 tcp dpt:68

Chain LIBVIRT_FWO (1 references)
pkts bytes target prot opt in out source destination
0 0 ACCEPT all -- virbr-nat eno1 192.168.10.0/24 0.0.0.0/0
0 0 REJECT all -- virbr-nat * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable

Chain LIBVIRT_FWI (1 references)
pkts bytes target prot opt in out source destination
0 0 ACCEPT all -- eno1 virbr-nat 0.0.0.0/0 192.168.10.0/24 ctstate RELATED,ESTABLISHED
0 0 REJECT all -- * virbr-nat 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable

Chain LIBVIRT_FWX (1 references)
pkts bytes target prot opt in out source destination
0 0 ACCEPT all -- virbr-nat virbr-nat 0.0.0.0/0 0.0.0.0/0

可以看到创建完虚拟网络后,filter表中新增了nat-network的一些规则。iptables中filter表主要用于流量的过滤,所以新增的规则也都是对进出虚拟机的流量做出了限制。

链LIBVIRT_INP中新增了进入nat-network网络的一些过滤规则,包括指定流量进入的设备必须是网桥virbr-nat,流量的协议tcp或者udp以及流量的端口号。链LIBVIRT_OUT中新增从nat-work网络出来的流量的过滤规则,包括指定流量离去的设备必须是网桥virbr-nat,流量的协议tcp或者udp以及流量的端口号。不难看出filter表中的链LIBVIRT_INP和链LIBVIRT_OUT实现了虚拟机安全组的功能,它们定义了虚拟网络进出流量的规则,可以通过修改规则实现对虚拟机流量的控制。

对于需要进行转发的流量,FORWARD链下的三条链也清晰定义了规则。三条链分别对应三种情况,LIBVIRT_FWX对应的是nat网络中虚拟机之间的互相访问。LIBVIRT_FWI对应的是外部网络访问虚拟机,LIBVIRT_FWO对应的是虚拟机访问外部网络。LIBVIRT_FWX中的一条规则,就是同一网络下(这里是同一网络设备,可以看作是同一网络)当一台虚拟机访问另一台虚拟机时,该流量是不是应该被过滤,答案肯定是否定的。LIBVIRT_FWI中的两条规则表示只有当目的地址为192.168.10.0/24,且流量的入口是eno1,出口是网桥设备virbr-nat,这样的流量才被接收。同样的LIBVIRT_FWO中的两条规则表示只有当源地址为192.168.10.0/24,且从流量的入口是网桥virbr-nat,出口是eno1,这样的流量才会被接收,不被过滤掉。

查看nat表新增的规则。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
iptables -t nat -vnL
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination

Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
3417 244K LIBVIRT_PRT all -- * * 0.0.0.0/0 0.0.0.0/0

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination

Chain LIBVIRT_PRT (1 references)
pkts bytes target prot opt in out source destination
0 0 RETURN all -- * eno1 192.168.10.0/24 224.0.0.0/24
0 0 RETURN all -- * eno1 192.168.10.0/24 255.255.255.255
0 0 MASQUERADE tcp -- * eno1 192.168.10.0/24 !192.168.10.0/24 masq ports: 1024-65535
0 0 MASQUERADE udp -- * eno1 192.168.10.0/24 !192.168.10.0/24 masq ports: 1024-65535
0 0 MASQUERADE all -- * eno1 192.168.10.0/24 !192.168.10.0/24

iptables中nat表主要用主要用来修改数据包的IP地址、端口号信息实现网络地址转换和端口转发。可以看到新增的规则集中在LIBVIRT_PRT链里。先看第一条规则。

1
2
pkts bytes target     prot opt in     out     source               destination         
0 0 RETURN all -- * eno1 192.168.10.0/24 224.0.0.0/24

其中224.0.0.0/24是组播的地址,所以不需要进行地址转换的操作,直接RETURNRETURN表示立即结束在目前规则链中的过滤程序,返回主规则链继续过滤。如果把自定义规则链看成是一个子程序,那么这个动作,就相当提早结束子程序并返回到主程序中。

第二条规则。

1
2
pkts bytes target     prot opt in     out     source               destination                 
0 0 RETURN all -- * eno1 192.168.10.0/24 255.255.255.255

255.255.255.255是广播的地址,所以不需要进行地址转换的操作,直接RETURN

其他规则。

1
2
3
4
pkts bytes target     prot opt in     out     source               destination                     
0 0 MASQUERADE tcp -- * eno1 192.168.10.0/24 !192.168.10.0/24 masq ports: 1024-65535
0 0 MASQUERADE udp -- * eno1 192.168.10.0/24 !192.168.10.0/24 masq ports: 1024-65535
0 0 MASQUERADE all -- * eno1 192.168.10.0/24 !192.168.10.0/24

上面的这三条规则定义了当流量的源地址是192.168.10.0/24且目的地址不是192.168.10.0/24(非同一网络下虚拟机互相访问的情况),需要进行NAT(网络地址转换)。其中MASQUERADE的作用类似SNAT(源地址转换),区别是SNAT需要显示指定转换的地址,而MASQURADE会根据出口网卡地址的IP自动设置转换的源IP地址(这里是eno1的IP地址)。masq ports指定了做NAT时的端口范围,只有在协议为TCP或者UDP时才会生效。out定义了网络流量的出口在宿主机的网卡eno1。

看到上面三条规则,就能解释为什么NAT模式下网络中的虚拟机可以访问外网,但是外部网络却不能直接访问虚拟机。主要原因是iptables规则只增加了源地址转换(SNAT),却没有目的地址转换(DNAT)。

路由规则

routed网络创建后,宿主机上会新增一个192.168.10.0/24网段的路由规则。

1
2
3
4
ip route
default via 10.12.17.1 dev eno1 proto dhcp metric 100
10.12.17.0/24 dev eno1 proto kernel scope link src 10.12.17.200 metric 100
192.168.10.0/24 dev virbr-nat proto kernel scope link src 192.168.10.1 linkdown

创建虚拟机

最后利用virt-install命令创建虚拟机。

1
2
3
4
5
6
7
8
9
sudo virt-install \
--connect=qemu:///system \
--virt-type kvm \
--name=myhost \
--vcpus=1 \
--ram=512 \
--disk cirros-0.6.1-x86_64-disk.img,format=qcow2 \
--import \
--network network=nat-network

其中--network用于指定虚拟机的网络。--name指定虚拟机的名称为myhost,正好对应网络配置文件中host的name属性,所以根据配置文件,虚拟机的IP地址应该为192.168.10.10。

创建完虚拟机后,可以查看网桥上的设备,发现网桥virbr-nat多了一个名为vnet5的设备。

1
2
3
brctl show
bridge name bridge id STP enabled interfaces
virbr-nat 8000.5254004dcf1b yes vnet5

查看vnet5的详细信息。

1
2
3
4
5
6
ip a show vnet5
vnet5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master virbr-nat state UNKNOWN group default qlen 1000
link/ether fe:54:00:ec:49:66 brd ff:ff:ff:ff:ff:ff
inet6 fe80::fc54:ff:feec:4966/64 scope link
valid_lft forever preferred_lft forever

利用命令virsh dumpxml myhost查看虚拟机的xml配置文件中网卡的设置。

1
2
3
4
5
6
7
8
9
10
11
12
13
<domain type='kvm' id='7'>
... ...
<devices>
<interface type='network'>
<mac address='52:54:00:f4:6a:43'/>
<source network='nat-network' portid='f3f9f940-cc95-4801-a43a-f5807cf44cae' bridge='virbr-nat'/>
<target dev='vnet5'/>
<model type='e1000'/>
<alias name='net0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
</devices>
</domain>

其中52:54:00:f4:6a:43是虚拟机的mac地址。对于配置文件的解读之后会在另一篇文章单独分析。

可以使用命令查看虚拟网络的DHCP租约的相关情况。

1
2
3
4
virsh net-dhcp-leases nat-network 
Expiry Time MAC 地址 Protocol IP address Hostname Client ID or DUID
-----------------------------------------------------------------------------------------------------------
2023-03-07 15:37:49 52:54:00:f4:6a:43 ipv4 192.168.10.10/24 - 01:52:54:00:f4:6a:43

网络测试

利用ping命令测试网络,先从虚拟机ping宿主机,模拟虚拟机访问宿主机。

1
2
3
4
5
6
7
8
9
10
11
ping -c 5 10.12.17.200
PING 10.12.17.200 (10.12.17.200) 56(84) bytes of data.
64 bytes from 10.12.17.200: icmp_seq=1 ttl=64 time=0.170 ms
64 bytes from 10.12.17.200: icmp_seq=2 ttl=64 time=0.357 ms
64 bytes from 10.12.17.200: icmp_seq=3 ttl=64 time=0.441 ms
64 bytes from 10.12.17.200: icmp_seq=4 ttl=64 time=0.246 ms
64 bytes from 10.12.17.200: icmp_seq=5 ttl=64 time=0.237 ms

--- 10.12.17.200 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4028ms
rtt min/avg/max/mdev = 0.170/0.290/0.441/0.096 ms

然后用宿主机ping虚拟机。

1
2
3
4
5
6
7
8
9
10
11
ping -c 5 192.168.10.10
PING 192.168.10.10 (192.168.10.10) 56(84) bytes of data.
64 bytes from 192.168.10.10: icmp_seq=1 ttl=64 time=0.251 ms
64 bytes from 192.168.10.10: icmp_seq=2 ttl=64 time=0.226 ms
64 bytes from 192.168.10.10: icmp_seq=3 ttl=64 time=0.290 ms
64 bytes from 192.168.10.10: icmp_seq=4 ttl=64 time=0.198 ms
64 bytes from 192.168.10.10: icmp_seq=5 ttl=64 time=0.273 ms

--- 192.168.10.10 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 68ms
rtt min/avg/max/mdev = 0.198/0.247/0.290/0.037 ms

用虚拟机ping另一台物理机。

1
2
3
4
5
6
7
8
9
10
11
ping -c 5 10.12.17.116
PING 10.12.17.116 (10.12.17.116) 56(84) bytes of data.
64 bytes from 10.12.17.116: icmp_seq=1 ttl=64 time=0.488 ms
64 bytes from 10.12.17.116: icmp_seq=2 ttl=64 time=0.383 ms
64 bytes from 10.12.17.116: icmp_seq=3 ttl=64 time=0.435 ms
64 bytes from 10.12.17.116: icmp_seq=4 ttl=64 time=0.332 ms
64 bytes from 10.12.17.116: icmp_seq=5 ttl=64 time=0.349 ms

--- 10.12.17.116 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 108ms
rtt min/avg/max/mdev = 0.332/0.397/0.488/0.060 ms

最后在另一台上物理机ping虚拟机。

1
2
3
4
5
6
7
8
9
10
11
ping -c 5 192.168.10.10
PING 192.168.10.10 (192.168.10.10) 56(84) bytes of data.
From 192.168.10.1 icmp_seq=1 Destination Host Unreachable
From 192.168.10.1 icmp_seq=2 Destination Host Unreachable
From 192.168.10.1 icmp_seq=3 Destination Host Unreachable
From 192.168.10.1 icmp_seq=4 Destination Host Unreachable
From 192.168.10.1 icmp_seq=5 Destination Host Unreachable

--- 192.168.10.10 ping statistics ---
5 packets transmitted, 0 received, +5 errors, 100% packet loss, time 79ms
pipe 4

由以上可以得出,NAT模式下的虚拟机可以和宿主机互相访问,同时能访问外部网络,但是不能被外部网络访问。

Routed模式

Routed模式(路由模式)相当于虚拟机连接到一台路由器上,由路由器(宿主机物理网卡),统一转发,但是不会修改源地址。

使用Routed模式时,虚拟交换机连接到连接到宿主机的物理局域网,在不使用NAT的情况下来回传递流量。虚拟交换机可以检查所有流量,并根据网络数据包中包含的信息来做出路由决策。情况却不总是理想的,因为在没有手动配置物理路由器的情况下,物理网络上没有其他主机物理机器知道虚拟机,所以无法访问虚拟机。
Network Routed

创建网络

首先确保宿主机的IP转发已经打开。

1
2
3
cat /proc/sys/net/ipv4/ip_forward
# IP转发打开,值为1。
1

如果没有打开,利用下面的命令打开IP地址转发。

1
sudo sysctl -w net.ipv4.ip_forward=1

查看宿主机的网络设备,eno1。

1
2
3
4
5
6
7
ip a
eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:e0:70:e8:fd:b7 brd ff:ff:ff:ff:ff:ff
inet 10.12.17.200/24 brd 10.12.17.255 scope global dynamic noprefixroute eno1
valid_lft 26998sec preferred_lft 26998sec
inet6 fe80::1f78:1d6:7d71:8430/64 scope link noprefixroute
valid_lft forever preferred_lft forever

创建一个routed模式的网络,下面是网络的详细配置文件routed-network.xml。

1
2
3
4
5
6
7
8
9
10
11
<network>
<name>routed-network</name>
<forward mode='route' dev='eno1'/>
<bridge name='virbr-routed' stp='on' delay='2'/>
<ip address='192.168.20.1' netmask='255.255.255.0'>
<dhcp>
<range start='192.168.20.2' end='192.168.20.254'/>
<host name='myhost' ip='192.168.20.20'/>
</dhcp>
</ip>
</network>

先解读一下routed-network.xml的配置文件。

着重看下第三行,上文说过forward表明虚拟网络将连接到物理LAN,forward的mode(模式)属性设置成route(路由模式),可以类比NAT模式的网络,nat表示连接到此网络的虚拟机和物理网络之间的所有流量将通过宿主机的IP路由堆栈转发到物理网络,之后虚拟机的IP地址被转换为宿主机的IP地址(NAT,网络地址转换),route模式和它类似,只是将虚拟机网络流量通过宿主机的IP路由规则转发到物理网络,但不会应用NAT。

然后利用libvirt的命令创建虚拟网络nat-network。

1
2
3
4
5
6
7
8
9
10
virsh net-define routed-network.xml
virsh net-start routed-network
virsh net-autostart routed-network

# 查看网络列表
virsh net-list --all
名称 状态 自动开始 持久
--------------------------------------------
default 不活跃 否 是
routed-network 活动 是 是

网络设备

创建好nat-network后,系统会自动创建一个网络设备virbr-routed,且它的IP地址是192.168.20.1/24。

1
2
3
4
5
ip a
virbr-routed: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
link/ether 52:54:00:58:71:34 brd ff:ff:ff:ff:ff:ff
inet 192.168.20.1/24 brd 192.168.20.255 scope global virbr-routed
valid_lft forever preferred_lft forever

利用brctl命令查看网桥设备。

1
2
3
brctl show
bridge name bridge id STP enabled interfaces
virbr-routed 8000.525400233d8e yes

brctl命令可以通过yum install -y bridge-utils来安装。

iptables规则

先看网络创建后的iptables的filter表的规则。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
iptables -vnL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
805K 450M LIBVIRT_INP all -- * * 0.0.0.0/0 0.0.0.0/0

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
521 31520 LIBVIRT_FWX all -- * * 0.0.0.0/0 0.0.0.0/0
521 31520 LIBVIRT_FWI all -- * * 0.0.0.0/0 0.0.0.0/0
517 31035 LIBVIRT_FWO all -- * * 0.0.0.0/0 0.0.0.0/0

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
704K 112M LIBVIRT_OUT all -- * * 0.0.0.0/0 0.0.0.0/0

Chain LIBVIRT_INP (1 references)
pkts bytes target prot opt in out source destination
0 0 ACCEPT udp -- virbr-routed * 0.0.0.0/0 0.0.0.0/0 udp dpt:53
0 0 ACCEPT tcp -- virbr-routed * 0.0.0.0/0 0.0.0.0/0 tcp dpt:53
0 0 ACCEPT udp -- virbr-routed * 0.0.0.0/0 0.0.0.0/0 udp dpt:67
0 0 ACCEPT tcp -- virbr-routed * 0.0.0.0/0 0.0.0.0/0 tcp dpt:67

Chain LIBVIRT_OUT (1 references)
pkts bytes target prot opt in out source destination
0 0 ACCEPT udp -- * virbr-routed 0.0.0.0/0 0.0.0.0/0 udp dpt:53
0 0 ACCEPT tcp -- * virbr-routed 0.0.0.0/0 0.0.0.0/0 tcp dpt:53
0 0 ACCEPT udp -- * virbr-routed 0.0.0.0/0 0.0.0.0/0 udp dpt:68
0 0 ACCEPT tcp -- * virbr-routed 0.0.0.0/0 0.0.0.0/0 tcp dpt:68

Chain LIBVIRT_FWO (1 references)
pkts bytes target prot opt in out source destination
0 0 ACCEPT all -- virbr-routed eno1 192.168.20.0/24 0.0.0.0/0
0 0 REJECT all -- virbr-routed * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable

Chain LIBVIRT_FWI (1 references)
pkts bytes target prot opt in out source destination
0 0 ACCEPT all -- eno1 virbr-routed 0.0.0.0/0 192.168.20.0/24
0 0 REJECT all -- * virbr-routed 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable

Chain LIBVIRT_FWX (1 references)
pkts bytes target prot opt in out source destination
0 0 ACCEPT all -- virbr-routed virbr-routed 0.0.0.0/0 0.0.0.0/0

可以看到filter表中新增的规则和NAT网络创建完成后新增的规则基本一致,功能基本都是对网络流量的过滤。

看一下nat表中新增的规则。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
iptables -t nat -vnL
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination

Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
53394 3746K LIBVIRT_PRT all -- * * 0.0.0.0/0 0.0.0.0/0

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination

Chain LIBVIRT_PRT (1 references)
pkts bytes target prot opt in out source destination

nat表中并未增加任何的新的规则。

路由规则

routed网络创建后,宿主机上会新增一个192.168.20.0/24网段的路由规则。

1
2
3
4
ip route
default via 10.12.17.1 dev eno1 proto dhcp metric 100
10.12.17.0/24 dev eno1 proto kernel scope link src 10.12.17.200 metric 100
192.168.20.0/24 dev virbr-routed proto kernel scope link src 192.168.20.1 linkdown

创建虚拟机

最后利用virt-install命令创建虚拟机。

1
2
3
4
5
6
7
8
9
sudo virt-install \
--connect=qemu:///system \
--virt-type kvm \
--name=myhost \
--vcpus=1 \
--ram=512 \
--disk cirros-0.6.1-x86_64-disk.img,format=qcow2 \
--import \
--network network=routed-network
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
sudo virt-install \
--connect=qemu:///system \
--virt-type qemu \
--name=myhost \
--machine q35 \
--vcpus=4 \
--ram=4096 \
--os-type=generic \
--disk path=/home/uniontechos-server-20-1060a-amd64.qcow2,format=qcow2,bus=virtio \
--boot uefi \
--import \
--graphics vnc,port=9527



sudo virt-install \
--connect=qemu:///system \
--name=test-smart \
--vcpus=4 \
--ram=4096 \
--disk path=/home/wkt/smart-20-Standard-1.0.0-arm64.qcow2,format=qcow2,bus=virtio \
--boot uefi \
--import \
--graphics vnc,listen=10.10.15.14,port=9527

sudo virt-install --virt-type qemu --name 1050a --ram 4096 \
--cdrom=/home/uniontechos-server-20-1050a-amd64-release-20220214.iso \
--disk 1050a.qcow2,bus=virtio,size=5,format=qcow2 \
--network network=default \
--graphics vnc,port=9527 \
--boot uefi \
--os-type=linux --os-variant=generic

sudo virt-install --connect=qemu:///system --virt-type qemu --name=myhost --vcpus=4 --ram=4096 --disk uniontechos-server-20-1060a-amd64.qcow2,format=qcow2 --import --boot uefi

sudo virt-install --name smart --vcpus=6 --ram 4096 --cdrom=uniontechos-smart-20-Standard-1.0.0-ARM64-arm64-generic_generic_1-20230228-1144.iso --disk smart.qcow2,bus=virtio,size=20,format=qcow2 --graphics vnc,listen=172.16.0.145,port=9527 --os-type=linux --os-variant=generic --boot uefi
1
<loader readonly='yes' secure='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader>

Routed模式下的虚拟机可以与宿主机相互通信,Routed模式中的虚拟机无法与外部网络互相通信,这是因为虚拟机流量发送到外部网络的主机时,源地址是虚拟网络的地址(这里是192.168.20.0/24),内网地址无法与外部网络直接通信,且routed模式也没对源地址处理,将其转换为宿主机网卡的IP地址,因此,外部网络发送的响应报文中的目标地址为虚拟机的IP地址时,无法到达宿主机的物理网卡,虚拟机也无法收到响应报文。

创建完虚拟机后,可以查看网桥上的设备,发现网桥virbr-nat多了一个名为vnet6的设备。

1
2
3
brctl show
bridge name bridge id STP enabled interfaces
virbr-routed 8000.525400233d8e yes vnet6

查看vnet6的详细信息。

1
2
3
4
5
ip a show vnet6
vnet6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master virbr-routed state UNKNOWN group default qlen 1000
link/ether fe:54:00:f4:6a:43 brd ff:ff:ff:ff:ff:ff
inet6 fe80::fc54:ff:fef4:6a43/64 scope link
valid_lft forever preferred_lft forever

利用命令virsh dumpxml myhost查看虚拟机的xml配置文件中网卡的设置。

1
2
3
4
5
6
7
8
9
10
11
12
13
<domain type='kvm' id='7'>
... ...
<devices>
<interface type='network'>
<mac address='52:54:00:f4:6a:43'/>
<source network='routed-network' portid='e8208650-019f-43d2-a359-fb8f80dc9afa' bridge='virbr-routed'/>
<target dev='vnet6'/>
<model type='e1000'/>
<alias name='net0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
</devices>
</domain>

其中52:54:00:f4:6a:43是虚拟机的mac地址。

网络测试

利用ping命令测试网络,先从虚拟机ping宿主机,模拟虚拟机访问宿主机。

1
2
3
4
5
6
7
8
9
10
11
ping -c 5 10.12.17.200
PING 10.12.17.200 (10.12.17.200) 56(84) bytes of data.
64 bytes from 10.12.17.200: icmp_seq=1 ttl=64 time=0.232 ms
64 bytes from 10.12.17.200: icmp_seq=2 ttl=64 time=0.270 ms
64 bytes from 10.12.17.200: icmp_seq=3 ttl=64 time=0.186 ms
64 bytes from 10.12.17.200: icmp_seq=4 ttl=64 time=0.425 ms
64 bytes from 10.12.17.200: icmp_seq=5 ttl=64 time=0.299 ms

--- 10.12.17.200 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4052ms
rtt min/avg/max/mdev = 0.186/0.282/0.425/0.080 ms

然后用宿主机ping虚拟机。

1
2
3
4
5
6
7
8
9
10
11
ping -c 5 192.168.20.20
PING 192.168.20.20 (192.168.20.20) 56(84) bytes of data.
64 bytes from 192.168.20.20: icmp_seq=1 ttl=64 time=0.183 ms
64 bytes from 192.168.20.20: icmp_seq=2 ttl=64 time=0.170 ms
64 bytes from 192.168.20.20: icmp_seq=3 ttl=64 time=0.190 ms
64 bytes from 192.168.20.20: icmp_seq=4 ttl=64 time=0.288 ms
64 bytes from 192.168.20.20: icmp_seq=5 ttl=64 time=0.210 ms

--- 192.168.20.254 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 57ms
rtt min/avg/max/mdev = 0.170/0.208/0.288/0.042 ms

用虚拟机ping另一台物理机。

1
2
3
4
5
6
7
8
9
10
11
ping -c 5 10.12.17.116
PING 10.12.17.116 (10.12.17.116) 56(84) bytes of data.
From 192.168.20.20 icmp_seq=1 Destination Host Unreachable
From 192.168.20.10 icmp_seq=2 Destination Host Unreachable
From 192.168.20.10 icmp_seq=3 Destination Host Unreachable
From 192.168.20.10 icmp_seq=4 Destination Host Unreachable
From 192.168.20.10 icmp_seq=5 Destination Host Unreachable

--- 10.12.17.16 ping statistics ---
5 packets transmitted, 0 received, +5 errors, 100% packet loss, time 35ms
pipe 4

最后在另一台上物理机ping虚拟机。

1
2
3
4
5
6
7
8
9
10
11
ping -c 5 192.168.20.20
PING 192.168.20.20 (192.168.20.20) 56(84) bytes of data.
From 192.168.20.1 icmp_seq=1 Destination Host Unreachable
From 192.168.20.1 icmp_seq=2 Destination Host Unreachable
From 192.168.20.1 icmp_seq=3 Destination Host Unreachable
From 192.168.20.1 icmp_seq=4 Destination Host Unreachable
From 192.168.20.1 icmp_seq=5 Destination Host Unreachable

--- 192.168.20.20 ping statistics ---
5 packets transmitted, 0 received, +5 errors, 100% packet loss, time 65ms
pipe 4

由以上可以得出,routed模式下的虚拟机可以和宿主机互相访问,但是不能访问外部网络,也不能被外部网络访问。

Isolated模式

Isolated模式(隔离模式)也称host-only(仅主机)模式,其模式的特点是同一网络下的所有虚拟机可以通信,同时也可以和宿主机进行通信,但是流量无法穿过虚拟网络,也收不到外网的流量,也就是无法和同一网络外的其他设备进行通信。简而言之,Isolated模式是将虚拟机网络和外部网络隔离出来。
Network Isolated

Bridged模式

使用Bridged模式(桥接模式)时,所有虚拟机都与宿主机位于同一子网中。同一物理网络上的所有其他物理机都知道虚拟机,并且可以访问虚拟机。该模式的特点是通过创建一个虚拟网卡,为该虚拟机网卡分配可以访问外部网络的IP地址,此时的物理网卡相当于一台交换机设备,虚拟机相当于宿主机所在的局域网内单独的一台物理机,它和宿主机的地位是同等的,没有依存关系。
Network Bridged

创建网络

首先需要创建一个网桥br0用于桥接虚拟机和宿主机网卡。