macvtap

义项:Linux虚拟网络设备
macvtap

macvtap 是 Linux 内核中的一类虚拟网络设备与配套的字符设备驱动,它把 macvlan 接口和 tap 设备结合起来,让 QEMU、KVM 等虚拟化工具可以像使用传统 tap 设备那样,把虚拟机直接接入物理网络。使用 macvtap 不需要在宿主机上搭建桥接设备,虚拟机会以独立的 MAC 地址出现在物理网段上。该驱动由 Arnd Bergmann 编写,2010 年进入 Linux 内核。

目录
  1. 定义
  2. 原理
  3. 发展历程
  4. 应用
  5. 局限
  6. 参见

定义

macvtap 是 Linux 内核 提供的一种网络设备类型,它在 macvlan 网络接口的基础上附加了一个 tap 字符设备,使同一套配置既能作为普通网络接口被管理和统计,又能通过字符设备向用户态程序收发数据帧[1]。创建 macvtap 接口的方式与创建 macvlan 接口相同,都用 ip link 命令,区别在于数据通路走字符设备而不是网络协议栈[1]。每个 macvtap 接口都拥有自己的字符设备节点,因此在权限管理上比通用的 tun/tap 驱动更简单[1]。

在内核配置中,该功能对应 CONFIG_MACVTAP 选项,其描述为基于 MAC-VLAN 的 tap 驱动,依赖 CONFIG_MACVLAN,可以编译为名为 macvtap 的模块[1]。在 libvirt 等管理工具中,这类接口以 type='direct' 的形式出现[2]。

原理

macvtap 的核心对象是一条队列,它把一个已打开的字符设备与一个 macvlan 接口连接起来,一个接口上可以存在多条队列,并与底层硬件的多队列相对应。队列通过套接字分配机制创建,收发路径分别由 aio_read 与 aio_write 等一系列文件操作实现,用户态程序可按帧读写[3]。

在数据方向上,来自外部物理接口的报文会被推入队列,等待用户态读取;用户态写入的报文则经由 macvlan 的发送路径送往下层设备[4]。若下层设备同时支持高位 DMA 与分散聚集,驱动还会打开零拷贝标志,使客户机内核与宿主内核之间的数据可以不经过额外复制。当接口存在多条队列时,驱动按报文的接收队列索引或流哈希选择队列,都失败时退回第一条可用队列。

发展历程

macvtap 驱动由 Arnd Bergmann 编写。其提交说明提到,为了让 macvlan 能够被 qemu 等需要 tap 文件描述符的工具使用,该驱动加入了一个小型后端,提供与 tun 驱动接口相同的字符设备,但只保留最少的功能[1]。这份补丁的提交时间为 2010 年 1 月 30 日,由 David S. Miller 于 2010 年 2 月 3 日合并[5]。

2013 年 12 月,Vlad Yasevich 提交补丁,使 macvtap 在收发两侧的行为与 macvlan 基本一致:发送侧改用 dev_queue_xmit,接收侧改用 netif_rx 与 dev_forward_skb,并给 macvtap 网络设备挂上自己的接收处理函数。这次改动之后,用户可以在 macvtap 设备上抓包,并对其施加 tc 动作[4]。此前的实现会在 skb->dev 尚未正确设置时就把报文从网络栈中取走,因此无法抓包[6]。

后续内核继续为其增加多队列支持与网络命名空间支持:多队列版本将队列组织为数组,并区分 numqueues 与 numvtaps;命名空间补丁则让 macvtap 设备类不再在不同网络命名空间之间共享 sysfs 层级[7][8]。

应用

macvtap 主要用于把虚拟机网卡直接接到宿主机的某个物理接口上。libvirt 的域 XML 中,这种连接写成 ,其中 source 元素的 dev 属性指定宿主机网卡名称,mode 属性指定工作模式[9]。IBM 的文档示例中同时给出 virtio 网卡模型与 vhost 驱动,并说明 MAC 地址字段可选,省略时由 libvirtd 自动生成[9]。

模式选项有 4 种。vepa 模式下客户机报文全部发往外部交换机,交换机需支持 hairpin 才能把同一主机上客户机之间的报文送回;bridge 模式下同一主机上的目的地由目标 macvtap 设备直接接收,但收发双方都必须处于 bridge 模式;private 模式下同一主机上的客户机彼此不能直接通信,报文需绕经外部路由器或网关;passthrough 模式把物理接口或 SR-IOV 虚拟功能直接交给一个客户机,该设备不能被多个客户机共享[2]。

手工创建一条 macvtap 接口时,需要指定下层网卡、接口名与模式,随后该接口对应的 /dev/tap 设备节点会自动出现,QEMU 可以打开它并配合 tap 后端使用[10]。由于不需要建立桥接,这类配置通常比传统桥接网络更简单,且每台虚拟机使用独立的 macvtap 接口[10]。在虚拟化场景之外,macvtap 也常与 ipvtap 并列提及,后者基于 ipvlan 而非 macvlan[11]。

局限

最常被提及的限制是宿主机与客户机之间无法直接通信。libvirt 的说明指出,这并非缺陷,而是 macvtap 的既定行为:宿主机物理网卡接入 macvtap 桥的方式,使客户机转发到物理接口的流量无法被回送到宿主机的 IP 协议栈,宿主协议栈发往物理接口的流量同样无法回送到 macvtap 桥再转给客户机[12]。因此客户机可以访问外部网络和同一主机上的其他客户机,却无法访问本机的宿主机[13]。virt-manager 的配置界面也提示,多数配置下 macvtap 无法用于宿主机到客户机的通信[2]。常见绕行办法是为宿主机另建一条 macvtap 接口,或另建一个仅含宿主机与客户机的隔离网络[12]。

另一项限制与源 MAC 地址有关。在 libvirt 社区的讨论中,macvtap 接口不会转发源 MAC 地址与该接口自身 MAC 不同的流量,因此如果客户机内部再架桥,回复报文会在到达客户机前被丢弃;自 libvirt 1.2.10 起,libvirt 会监听客户机内发起的 MAC 地址变更并相应调整宿主机一侧的配置[14]。此外,macvtap 接口不能使用已经连接到 Linux 网桥的网络接口[15]。

参见

  • macvlan —— macvtap 在其基础上构建,共享接口创建方式与模式设置。

  • tap 设备 —— macvtap 对外提供的字符设备接口与 tun/tap 驱动兼容。

  • KVM —— 常通过 macvtap 为虚拟机提供直接接入物理网络的网卡。

  • QEMU —— 可以打开 macvtap 生成的字符设备作为网络后端。

  • libvirt —— 用 type='direct' 的域 XML 配置来管理 macvtap 接口。

  • 网络命名空间 —— macvtap 的设备类已支持按网络命名空间隔离。

参考资料

  1. github.com 上的网页 [引用日期2026-10-14]
  2. redhat.com 上的文件 [引用日期2026-10-14]
  3. Linux-Kernel Archive: [PATCH 3/3] net: macvtap driver [引用日期2026-10-14]
  4. macvtap [引用日期2026-10-14]
  5. net: macvtap driver - linux-yocto-4.4 [引用日期2026-10-14]
  6. 6acf54f1cf0a6747bac9fea26f34cfc5a9029523 [引用日期2026-10-14]
  7. macvtap [引用日期2026-10-14]
  8. 17af2bce88d31e65ed73d638bb752d2e13c66ced [引用日期2026-10-14]
  9. Linux on IBM Systems - Focus sentinel [引用日期2026-10-14]
  10. README [引用日期2026-10-14]
  11. Operativni sustavi i računalne mreže - Linux u primjeni(PDF) [引用日期2026-10-14]
  12. Guest_can_reach_outside_network_but_cant_reach_host_macvtap [引用日期2026-10-14]
  13. redhat.com 上的网页 [引用日期2026-10-14]
  14. 'Re: [libvirt-users] Limitations of macvtap devices?' [引用日期2026-10-14]
  15. book-virt_color_en(PDF) [引用日期2026-10-14]
词条评价
词条统计

浏览次数:5 次

阅读量:0 次 · 阅读完成量:0 次

最近更新:2026-10-13T18:22:55Z

历史版本

本条目引用的词条
Linux 内核 macvlan tap 设备 KVM QEMU libvirt 网络命名空间