我安装 Debian 虚拟机virt-install
的方式是让来宾获得一个名为的以太网接口vnet0
:
$ virsh domiflist git-server
Interface Type Source Model MAC
-------------------------------------------------------
vnet0 bridge br-ext rtl8139 52:54:00:a8:32:d7
$
这可以在检查qemu
命令行时确认:
-netdev tap,fd=27,id=hostnet0 -device rtl8139,netdev=hostnet0,id=net0,mac=52:54:00:a8:32:d7,bus=pci.0,addr=0x2
但是,主机中有一个同名的 TAP 设备vnet0
:
$ ethtool -i vnet0
driver: tun
version: 1.6
firmware-version:
expansion-rom-version:
bus-info: tap
supports-statistics: no
supports-test: no
supports-eeprom-access: no
supports-register-dump: no
supports-priv-flags: no
$
..但具有不同的MAC地址:
$ ip l sh vnet0
56: vnet0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master br-ext state UNKNOWN mode DEFAULT group default qlen 1000
link/ether fe:54:00:a8:32:d7 brd ff:ff:ff:ff:ff:ff
$
虚拟机接口和主机中的 TAP 设备究竟是如何连接的?还是只有一台 TAP 设备?如果是,那么 MAC 地址有何不同?
qemu
(或启动的包装程序qemu
或另一个模拟器)首先打开/dev/net/tun
设备多路复用器。这将返回一个文件描述符,可以通过ioctl(TUNSETIFF)
在字段中使用 TAP 接口的名称调用该 fd来将其附加到 TAP 接口ifreq->ifr.name
。如果已以这种方式附加了具有该名称的 TAP 接口,则该操作将失败。
然后 fd 可用于写入将出现在 TAP 接口上的数据包,就像从远程端接收到的一样,并读取内核通过 TAP 接口路由的数据包。
如果调用进程具有
CAP_NET_ADMIN
能力(例如 isroot
),并且具有该名称的 TAP 接口尚不存在,则会自动创建该接口。如果没有给出名称,将使用第一个空闲名称。作为多路复用器的事实
/dev/net/tun
意味着open()
每次将句柄返回到不同的“远程一半”时,它都会返回。而那个“远程一半”可以连接到单个 TAP 接口。此外,就像任何其他文件描述符一样,如果该程序能够以这种方式使用它(
qemu
与其-netdev tap,fd=FD
选项一样),则可以将其传递给另一个程序。opentap
在这个答案中查看一个非常简单的函数示例。更多细节 +内核文档中tuntap.txt中的示例代码。
不,每个客户都有一个单独的设备。将多个 TAP 设备连接到同一接口的方法是使用主机上的网桥。
主机上的界面和来宾上的界面完全不同;把它想象成一条虚拟的 UTP 电缆——两端的每个设备都有自己的 MAC。
设置来宾
-device ...,mac=...
上模拟设备的硬件地址,而不是主机上的 TAP 设备的硬件地址。