我第一次被PF和VF这两个词卡住,是在给一台服务器上的A100做GPU虚拟化的时候。当时的场景很典型:一张卡算力足够,但多个训练任务都想用,谁也不愿意排队等一整张卡。查了一堆资料,所有方案里都绕不开SR-IOV、Physical Function、Virtual Function,可一打开PCIe配置空间文档,全是一堆看不懂的寄存器描述。后来把Linux内核里SR-IOV相关代码和NVIDIA驱动加载日志对着看了一遍,才算是把PF和VF整条链路捋顺。
这篇文章定位在KMD(Kernel Mode Driver)专栏的2.3节,面向的是想搞懂GPU底层虚拟化原理的驱动开发者、虚拟化平台工程师,以及正在为AI训练容器分配GPU资源的人。它不打算复述PCI-SIG规范原文,而是带着你从“一张GPU怎么变成多张GPU”这个问题出发,把PF、VF的硬件身份、驱动加载路径、虚拟化交付方式和常见坑位全部过一遍。
1. PF和VF的硬件身份:理解PCIe设备的分身逻辑
1.1 一个PCIe设备为何需要“功能”这个概念
PCIe设备在总线上以“总线号:设备号:功能号”三元组标识。一个物理PCIe设备可以包含多个“功能”,每个功能有独立的配置空间、BAR(Base Address Register)空间和中断能力。
“功能”这个概念是理解PF/VF的起点。在传统PCIe里,端到端的设备(Endpoint)大多只有一个功能,比如显卡只有一个图形功能,声卡只有一个音频功能。多功能的例子是网卡同时提供管理接口和数据接口,所以常见是两个功能。
SR-IOV规范在单根虚拟化场景下,把“功能”这个概念扩展到了两个层面:
- Physical Function(PF) 是物理功能,承担完整的管理、配置和控制职责,拥有完整的PCIe配置空间,可以像普通设备一样被驱动完整操控。
- Virtual Function(VF) 是虚拟功能,是PF通过SR-IOV能力派生出来的轻量级功能,自身只有部分配置空间,不具备完整的系统资源管理能力,必须由PF驱动代为管理底层资源。
类比一下:PF是整栋楼的物业,掌握楼宇管道、电力和门禁的总控权;VF是租出去的几个单元,住户可以在单元里自由布置家具,但水电总闸、承重墙和消防通道仍然归物业管,住户只能看到自己单元的那块区域。
