SR-IOV Network Device Plugin 3.11.0 --- 超深度架构分析
第四部分:总体架构、模块关系、核心流程与设计决策
一、总体架构
1.1 系统架构全景图
#mermaid-svg-tWxuwLCkvdy9Mp1C{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-tWxuwLCkvdy9Mp1C .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-tWxuwLCkvdy9Mp1C .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-tWxuwLCkvdy9Mp1C .error-icon{fill:#552222;}#mermaid-svg-tWxuwLCkvdy9Mp1C .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-tWxuwLCkvdy9Mp1C .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-tWxuwLCkvdy9Mp1C .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-tWxuwLCkvdy9Mp1C .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-tWxuwLCkvdy9Mp1C .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-tWxuwLCkvdy9Mp1C .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-tWxuwLCkvdy9Mp1C .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-tWxuwLCkvdy9Mp1C .marker{fill:#333333;stroke:#333333;}#mermaid-svg-tWxuwLCkvdy9Mp1C .marker.cross{stroke:#333333;}#mermaid-svg-tWxuwLCkvdy9Mp1C svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-tWxuwLCkvdy9Mp1C p{margin:0;}#mermaid-svg-tWxuwLCkvdy9Mp1C .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-tWxuwLCkvdy9Mp1C .cluster-label text{fill:#333;}#mermaid-svg-tWxuwLCkvdy9Mp1C .cluster-label span{color:#333;}#mermaid-svg-tWxuwLCkvdy9Mp1C .cluster-label span p{background-color:transparent;}#mermaid-svg-tWxuwLCkvdy9Mp1C .label text,#mermaid-svg-tWxuwLCkvdy9Mp1C span{fill:#333;color:#333;}#mermaid-svg-tWxuwLCkvdy9Mp1C .node rect,#mermaid-svg-tWxuwLCkvdy9Mp1C .node circle,#mermaid-svg-tWxuwLCkvdy9Mp1C .node ellipse,#mermaid-svg-tWxuwLCkvdy9Mp1C .node polygon,#mermaid-svg-tWxuwLCkvdy9Mp1C .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-tWxuwLCkvdy9Mp1C .rough-node .label text,#mermaid-svg-tWxuwLCkvdy9Mp1C .node .label text,#mermaid-svg-tWxuwLCkvdy9Mp1C .image-shape .label,#mermaid-svg-tWxuwLCkvdy9Mp1C .icon-shape .label{text-anchor:middle;}#mermaid-svg-tWxuwLCkvdy9Mp1C .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-tWxuwLCkvdy9Mp1C .rough-node .label,#mermaid-svg-tWxuwLCkvdy9Mp1C .node .label,#mermaid-svg-tWxuwLCkvdy9Mp1C .image-shape .label,#mermaid-svg-tWxuwLCkvdy9Mp1C .icon-shape .label{text-align:center;}#mermaid-svg-tWxuwLCkvdy9Mp1C .node.clickable{cursor:pointer;}#mermaid-svg-tWxuwLCkvdy9Mp1C .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-tWxuwLCkvdy9Mp1C .arrowheadPath{fill:#333333;}#mermaid-svg-tWxuwLCkvdy9Mp1C .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-tWxuwLCkvdy9Mp1C .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-tWxuwLCkvdy9Mp1C .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-tWxuwLCkvdy9Mp1C .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-tWxuwLCkvdy9Mp1C .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-tWxuwLCkvdy9Mp1C .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-tWxuwLCkvdy9Mp1C .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-tWxuwLCkvdy9Mp1C .cluster text{fill:#333;}#mermaid-svg-tWxuwLCkvdy9Mp1C .cluster span{color:#333;}#mermaid-svg-tWxuwLCkvdy9Mp1C div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-tWxuwLCkvdy9Mp1C .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-tWxuwLCkvdy9Mp1C rect.text{fill:none;stroke-width:0;}#mermaid-svg-tWxuwLCkvdy9Mp1C .icon-shape,#mermaid-svg-tWxuwLCkvdy9Mp1C .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-tWxuwLCkvdy9Mp1C .icon-shape p,#mermaid-svg-tWxuwLCkvdy9Mp1C .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-tWxuwLCkvdy9Mp1C .icon-shape .label rect,#mermaid-svg-tWxuwLCkvdy9Mp1C .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-tWxuwLCkvdy9Mp1C .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-tWxuwLCkvdy9Mp1C .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-tWxuwLCkvdy9Mp1C :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} SR-IOV Network Device Plugin
外部系统
NAD集成
工具层
CDI层
服务器层
资源池层
过滤层
信息提供者层
设备构建层
设备发现层
工厂层
入口层
Kubernetes API Server
Kubelet Device Plugin Manager
Container Runtime: CRI-O/containerd
Multus CNI
cmd/sriovdp/main.go
信号管理/生命周期
cmd/sriovdp/manager.go
resourceManager
pkg/factory/factory.go
resourceFactory
所有组件的创建中心
pkg/netdevice/
netDeviceProvider
PCI Class 0x02
pkg/accelerator/
accelDeviceProvider
PCI Class 0x12
pkg/auxnetdevice/
auxNetDeviceProvider
辅助设备
pkg/devices/host.go
HostDeviceImpl
基类+InfoProvider组合
pkg/devices/gen_pci.go
GenericPciDevice
PCI装饰器
pkg/devices/gen_net.go
GenericNetDevice
网络装饰器
pkg/devices/rdma.go
RdmaDeviceSpec
RDMA能力
pkg/devices/vfio.go
VfioDevice
VFIO能力
pkg/devices/vdpa.go
VdpaDeviceImpl
vDPA能力
infoprovider/genericInfoProvider
通用: deviceID
infoprovider/vfioInfoProvider
VFIO: /dev/vfio/*
infoprovider/uioInfoProvider
UIO: /dev/uioX
infoprovider/rdmaInfoProvider
RDMA: /dev/infiniband/*
infoprovider/vdpaInfoProvider
vDPA: /dev/vhost-vdpa-*
infoprovider/vhostNetInfoProvider
vhost: /dev/vhost-net
infoprovider/extraInfoProvider
额外: 自定义键值
pkg/resources/deviceSelectors.go
12个选择器
策略模式
pkg/netdevice/netResourcePool
网络资源池+NAD
pkg/accelerator/accelResourcePool
加速器资源池
pkg/auxnetdevice/auxNetResourcePool
辅助资源池
pkg/resources/server.go
resourceServer
gRPC Device Plugin
pkg/cdi/cdi.go
CDI Spec生成/注解
pkg/utils/utils.go
SYSFS操作
pkg/utils/netlink_provider.go
netlink封装
pkg/utils/sriovnet_provider.go
sriovnet封装
pkg/utils/rdma_provider.go
rdmamap封装
pkg/utils/vdpa_provider.go
govdpa封装
pkg/netdevice/nadutils.go
NAD信息存储
1.2 架构分层
| 层次 | 模块 | 职责 |
|---|---|---|
| 入口层 | cmd/sriovdp/ | 程序启动、CLI参数、信号处理、资源管理器编排 |
| 工厂层 | pkg/factory/ | 组件创建中心,所有对象的工厂方法 |
| 设备发现层 | pkg/netdevice/, accelerator/, auxnetdevice/ | PCI/辅助设备扫描与 HostDevice 构建 |
| 设备构建层 | pkg/devices/ | 设备基类与装饰器,InfoProvider 组合链 |
| 信息提供者层 | pkg/infoprovider/ | 各类设备文件/环境变量/挂载点的生成策略 |
| 过滤层 | pkg/resources/deviceSelectors.go | 12个设备选择器的策略模式实现 |
| 资源池层 | 三个子包中的 ResourcePool | 设备池管理、健康检查、环境变量/设备规格聚合 |
| 服务器层 | pkg/resources/server.go | gRPC Device Plugin 协议实现 |
| CDI层 | pkg/cdi/ | CDI 规范文件生成与容器注解 |
| 工具层 | pkg/utils/ | sysfs/netlink/sriovnet/rdmamap/govdpa 封装 |
| NAD集成 | pkg/netdevice/nadutils.go | Multus CNI 设备信息存储 |
二、25模块概览表
| # | 模块 | 关键类型 | 核心方法 | 依赖 | 行数(约) |
|---|---|---|---|---|---|
| 1 | cmd/sriovdp/main.go | cliParams | main, flagInit | manager, signal | 90 |
| 2 | cmd/sriovdp/manager.go | resourceManager | newResourceManager, readConfig, discoverHostDevices, initServers, startAllServers, stopAllServers | factory, types, utils, cdi | 260 |
| 3 | pkg/types/types.go | ResourceConfig, DeviceSelectors×5, 接口×8 | --- | pluginapi | 380 |
| 4 | pkg/factory/factory.go | resourceFactory | GetDeviceProvider, GetDefaultInfoProvider, GetSelector, GetResourcePool, GetDeviceFilter, FilterBySelector, GetRdmaSpec, GetVdpaDevice | types, netdevice, accelerator, auxnetdevice, infoprovider, resources | 300 |
| 5 | pkg/devices/api.go | APIDevice | GetDeviceSpecs, GetEnvVal, GetMounts, GetAPIDevice | pluginapi, types | 30 |
| 6 | pkg/devices/host.go | HostDeviceImpl | NewHostDeviceImpl, GetDeviceSpecs, GetEnvVal, GetMounts, GetAPIDevice + Getters | infoprovider, utils | 180 |
| 7 | pkg/devices/gen_pci.go | GenericPciDevice | NewGenericPciDevice, GetPciAddr, GetAcpiIndex | devices | 40 |
| 8 | pkg/devices/gen_net.go | GenericNetDevice | NewGenericNetDevice, GetPfNetName, GetNetName, IsRdma + Getters | devices, utils, factory | 150 |
| 9 | pkg/devices/rdma.go | RdmaDeviceSpec | NewRdmaDeviceSpec, IsRdma, GetRdmaDeviceSpec, GetRdmaDeviceName | utils, pluginapi | 120 |
| 10 | pkg/devices/vfio.go | VfioDevice | NewVfioDevice | utils | 30 |
| 11 | pkg/devices/vdpa.go | VdpaDeviceImpl | NewVdpaDeviceImpl, GetPath, GetType | utils, types, govdpa | 80 |
| 12 | pkg/infoprovider/generic.go | genericInfoProvider | GetName, GetDeviceSpecs, GetEnvVal, GetMounts | types, pluginapi | 40 |
| 13 | pkg/infoprovider/vfio.go | vfioInfoProvider | GetName, GetDeviceSpecs, GetEnvVal, GetMounts | types, utils, pluginapi | 60 |
| 14 | pkg/infoprovider/uio.go | uioInfoProvider | GetName, GetDeviceSpecs, GetEnvVal, GetMounts | types, utils, pluginapi | 50 |
| 15 | pkg/infoprovider/rdma.go | rdmaInfoProvider | GetName, GetDeviceSpecs, GetEnvVal, GetMounts | types, pluginapi | 70 |
| 16 | pkg/infoprovider/vdpa.go | vdpaInfoProvider | GetName, GetDeviceSpecs, GetEnvVal, GetMounts, isHealthy | types, pluginapi | 90 |
| 17 | pkg/infoprovider/vhost.go | vhostNetInfoProvider | GetName, GetDeviceSpecs, GetEnvVal, GetMounts, VhostNetDeviceExist | types, pluginapi | 70 |
| 18 | pkg/infoprovider/extra.go | extraInfoProvider | GetName, GetDeviceSpecs, GetEnvVal, GetMounts | types, pluginapi | 50 |
| 19 | pkg/netdevice/netDeviceProvider.go | netDeviceProvider | AddTargetDevices, GetDevices, GetFilteredDevices, ValidConfig | types, factory, devices, utils, infoprovider | 200 |
| 20 | pkg/netdevice/pciNetDevice.go | pciNetDevice | NewPciNetDevice, GetDDPProfiles, GetVdpaDevice, GetPKey, GetEnvVal | devices, utils | 100 |
| 21 | pkg/netdevice/netResourcePool.go | netResourcePool | NewNetResourcePool, GetDeviceSpecs, GetEnvs, Probe, StoreDeviceInfoFile | types, nadutils, utils | 180 |
| 22 | pkg/netdevice/nadutils.go | nadutils | NewNadUtils, DiscoverSriovNetworks, StoreDeviceInfoFile, CleanSriovNetworks | types, k8s/client-go | 150 |
| 23 | pkg/accelerator/accelDeviceProvider.go | accelDeviceProvider | AddTargetDevices, GetDevices, GetFilteredDevices | types, factory, devices | 120 |
| 24 | pkg/accelerator/accelDevice.go | accelDevice | NewAccelDevice | devices | 20 |
| 25 | pkg/accelerator/accelResourcePool.go | accelResourcePool | NewAccelResourcePool, GetCDIName | types | 60 |
续表:
| # | 模块 | 关键类型 | 核心方法 | 依赖 | 行数(约) |
|---|---|---|---|---|---|
| 26 | pkg/auxnetdevice/auxNetDeviceProvider.go | auxNetDeviceProvider | AddTargetDevices, GetDevices, GetFilteredDevices | types, factory, devices, utils | 160 |
| 27 | pkg/auxnetdevice/auxNetDevice.go | auxNetDevice | NewAuxNetDevice, GetAuxType + Getters | devices | 80 |
| 28 | pkg/auxnetdevice/auxNetResourcePool.go | auxNetResourcePool | NewAuxNetResourcePool, GetEnvs, Probe, StoreDeviceInfoFile, GetCDIName | types | 100 |
| 29 | pkg/resources/server.go | resourceServer | NewResourceServer, Start, Stop, Init, ListAndWatch, Allocate, GetDevicePrefix | types, cdi, pluginapi, grpc | 320 |
| 30 | pkg/resources/deviceSelectors.go | 12个 Selector | Filter (×12) | types, utils | 350 |
| 31 | pkg/resources/pool_stub.go | poolStub | 通用ResourcePool方法 | types | 90 |
| 32 | pkg/cdi/cdi.go | impl | CreateCDISpecForPool, CreateContainerAnnotations, CleanupSpecs | types, cdi/specs | 120 |
| 33 | pkg/utils/utils.go | --- | 30+工具函数(sysfs操作) | ghw, netlink | 500 |
| 34 | pkg/utils/netlink_provider.go | NetlinkProvider | GetLinkAttrs, GetDevLinkDeviceEswitchAttrs, GetIPv4RouteList, etc. | vishvananda/netlink | 130 |
| 35 | pkg/utils/sriovnet_provider.go | SriovnetProvider | GetUplinkRepresentor, GetPfPciFromAux, GetNetDevicesFromAux, etc. | sriovnet | 50 |
| 36 | pkg/utils/rdma_provider.go | RdmaProvider | GetRdmaDevicesForPcidev, GetRdmaDevicesForAuxdev, GetRdmaCharDevices | rdmamap | 30 |
| 37 | pkg/utils/vdpa_provider.go | VdpaProvider | GetVdpaDeviceByPci | govdpa | 30 |
三、模块间调用关系矩阵
3.1 调用关系图
#mermaid-svg-3hGzRCAqhwXel3GA{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-3hGzRCAqhwXel3GA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-3hGzRCAqhwXel3GA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-3hGzRCAqhwXel3GA .error-icon{fill:#552222;}#mermaid-svg-3hGzRCAqhwXel3GA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-3hGzRCAqhwXel3GA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-3hGzRCAqhwXel3GA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-3hGzRCAqhwXel3GA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-3hGzRCAqhwXel3GA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-3hGzRCAqhwXel3GA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-3hGzRCAqhwXel3GA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-3hGzRCAqhwXel3GA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-3hGzRCAqhwXel3GA .marker.cross{stroke:#333333;}#mermaid-svg-3hGzRCAqhwXel3GA svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-3hGzRCAqhwXel3GA p{margin:0;}#mermaid-svg-3hGzRCAqhwXel3GA .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-3hGzRCAqhwXel3GA .cluster-label text{fill:#333;}#mermaid-svg-3hGzRCAqhwXel3GA .cluster-label span{color:#333;}#mermaid-svg-3hGzRCAqhwXel3GA .cluster-label span p{background-color:transparent;}#mermaid-svg-3hGzRCAqhwXel3GA .label text,#mermaid-svg-3hGzRCAqhwXel3GA span{fill:#333;color:#333;}#mermaid-svg-3hGzRCAqhwXel3GA .node rect,#mermaid-svg-3hGzRCAqhwXel3GA .node circle,#mermaid-svg-3hGzRCAqhwXel3GA .node ellipse,#mermaid-svg-3hGzRCAqhwXel3GA .node polygon,#mermaid-svg-3hGzRCAqhwXel3GA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-3hGzRCAqhwXel3GA .rough-node .label text,#mermaid-svg-3hGzRCAqhwXel3GA .node .label text,#mermaid-svg-3hGzRCAqhwXel3GA .image-shape .label,#mermaid-svg-3hGzRCAqhwXel3GA .icon-shape .label{text-anchor:middle;}#mermaid-svg-3hGzRCAqhwXel3GA .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-3hGzRCAqhwXel3GA .rough-node .label,#mermaid-svg-3hGzRCAqhwXel3GA .node .label,#mermaid-svg-3hGzRCAqhwXel3GA .image-shape .label,#mermaid-svg-3hGzRCAqhwXel3GA .icon-shape .label{text-align:center;}#mermaid-svg-3hGzRCAqhwXel3GA .node.clickable{cursor:pointer;}#mermaid-svg-3hGzRCAqhwXel3GA .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-3hGzRCAqhwXel3GA .arrowheadPath{fill:#333333;}#mermaid-svg-3hGzRCAqhwXel3GA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-3hGzRCAqhwXel3GA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-3hGzRCAqhwXel3GA .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-3hGzRCAqhwXel3GA .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-3hGzRCAqhwXel3GA .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-3hGzRCAqhwXel3GA .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-3hGzRCAqhwXel3GA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-3hGzRCAqhwXel3GA .cluster text{fill:#333;}#mermaid-svg-3hGzRCAqhwXel3GA .cluster span{color:#333;}#mermaid-svg-3hGzRCAqhwXel3GA div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-3hGzRCAqhwXel3GA .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-3hGzRCAqhwXel3GA rect.text{fill:none;stroke-width:0;}#mermaid-svg-3hGzRCAqhwXel3GA .icon-shape,#mermaid-svg-3hGzRCAqhwXel3GA .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-3hGzRCAqhwXel3GA .icon-shape p,#mermaid-svg-3hGzRCAqhwXel3GA .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-3hGzRCAqhwXel3GA .icon-shape .label rect,#mermaid-svg-3hGzRCAqhwXel3GA .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-3hGzRCAqhwXel3GA .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-3hGzRCAqhwXel3GA .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-3hGzRCAqhwXel3GA :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 创建+编排
创建组件
发现设备
发现设备
发现设备
创建服务器
创建Provider
创建Provider
创建Provider
创建Selector
创建Pool
创建Pool
创建Pool
创建Server
创建InfoProvider
创建RdmaSpec
构建设备
装饰
装饰
组装
过滤
创建池
构建设备
装饰
组装
过滤
构建设备
组装
过滤
聚合
获取属性
获取属性
NAD集成
gRPC
CDI
持有
持有
持有
main.go
manager.go
factory.go
netDeviceProvider
accelDeviceProvider
auxNetDeviceProvider
server.go
deviceSelectors
netResourcePool
accelResourcePool
auxNetResourcePool
infoprovider/*
rdma.go
host.go
gen_net.go
gen_pci.go
pciNetDevice.go
accelDevice.go
auxNetDevice.go
utils.go
nadutils.go
Kubelet
cdi.go
3.2 核心调用路径
#mermaid-svg-TKGUvpRai8VqlIMO{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-TKGUvpRai8VqlIMO .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-TKGUvpRai8VqlIMO .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-TKGUvpRai8VqlIMO .error-icon{fill:#552222;}#mermaid-svg-TKGUvpRai8VqlIMO .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-TKGUvpRai8VqlIMO .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-TKGUvpRai8VqlIMO .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-TKGUvpRai8VqlIMO .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-TKGUvpRai8VqlIMO .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-TKGUvpRai8VqlIMO .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-TKGUvpRai8VqlIMO .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-TKGUvpRai8VqlIMO .marker{fill:#333333;stroke:#333333;}#mermaid-svg-TKGUvpRai8VqlIMO .marker.cross{stroke:#333333;}#mermaid-svg-TKGUvpRai8VqlIMO svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-TKGUvpRai8VqlIMO p{margin:0;}#mermaid-svg-TKGUvpRai8VqlIMO .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-TKGUvpRai8VqlIMO .cluster-label text{fill:#333;}#mermaid-svg-TKGUvpRai8VqlIMO .cluster-label span{color:#333;}#mermaid-svg-TKGUvpRai8VqlIMO .cluster-label span p{background-color:transparent;}#mermaid-svg-TKGUvpRai8VqlIMO .label text,#mermaid-svg-TKGUvpRai8VqlIMO span{fill:#333;color:#333;}#mermaid-svg-TKGUvpRai8VqlIMO .node rect,#mermaid-svg-TKGUvpRai8VqlIMO .node circle,#mermaid-svg-TKGUvpRai8VqlIMO .node ellipse,#mermaid-svg-TKGUvpRai8VqlIMO .node polygon,#mermaid-svg-TKGUvpRai8VqlIMO .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-TKGUvpRai8VqlIMO .rough-node .label text,#mermaid-svg-TKGUvpRai8VqlIMO .node .label text,#mermaid-svg-TKGUvpRai8VqlIMO .image-shape .label,#mermaid-svg-TKGUvpRai8VqlIMO .icon-shape .label{text-anchor:middle;}#mermaid-svg-TKGUvpRai8VqlIMO .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-TKGUvpRai8VqlIMO .rough-node .label,#mermaid-svg-TKGUvpRai8VqlIMO .node .label,#mermaid-svg-TKGUvpRai8VqlIMO .image-shape .label,#mermaid-svg-TKGUvpRai8VqlIMO .icon-shape .label{text-align:center;}#mermaid-svg-TKGUvpRai8VqlIMO .node.clickable{cursor:pointer;}#mermaid-svg-TKGUvpRai8VqlIMO .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-TKGUvpRai8VqlIMO .arrowheadPath{fill:#333333;}#mermaid-svg-TKGUvpRai8VqlIMO .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-TKGUvpRai8VqlIMO .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-TKGUvpRai8VqlIMO .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TKGUvpRai8VqlIMO .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-TKGUvpRai8VqlIMO .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TKGUvpRai8VqlIMO .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-TKGUvpRai8VqlIMO .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-TKGUvpRai8VqlIMO .cluster text{fill:#333;}#mermaid-svg-TKGUvpRai8VqlIMO .cluster span{color:#333;}#mermaid-svg-TKGUvpRai8VqlIMO div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-TKGUvpRai8VqlIMO .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-TKGUvpRai8VqlIMO rect.text{fill:none;stroke-width:0;}#mermaid-svg-TKGUvpRai8VqlIMO .icon-shape,#mermaid-svg-TKGUvpRai8VqlIMO .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TKGUvpRai8VqlIMO .icon-shape p,#mermaid-svg-TKGUvpRai8VqlIMO .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-TKGUvpRai8VqlIMO .icon-shape .label rect,#mermaid-svg-TKGUvpRai8VqlIMO .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TKGUvpRai8VqlIMO .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-TKGUvpRai8VqlIMO .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-TKGUvpRai8VqlIMO :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 分配路径
KL.Allocate → rs.Allocate → pool.GetDeviceSpecs → pool.GetEnvs → pool.GetMounts → cdi.CreateContainerAnnotations → pool.StoreDeviceInfoFile
服务器启动路径
rs.Start → rs.Init → cdi.CreateCDISpecForPool → gRPC Server → register/watch → triggerUpdate goroutine
过滤路径
dp.GetFilteredDevices → factory.FilterBySelector → selector.Filter × N
设备构建路径
dp.GetDevices → factory.GetDefaultInfoProvider → NewHostDeviceImpl → NewGenericNetDevice → NewGenericPciDevice → NewPciNetDevice
设备发现路径
discoverHostDevices → dp.AddTargetDevices → ghw.PCI → utils.IsSriovPF → utils.HasDefaultRoute → utils.IsNetlinkStatusUp
启动路径
main → newResourceManager → readConfig → discoverHostDevices → initServers → startAllServers
四、三大核心流程详解
4.1 流程一:插件启动与设备注册
Kubelet CDI ResourceServer ResourcePool DeviceSelector DeviceProvider ResourceFactory ResourceManager main Kubelet CDI ResourceServer ResourcePool DeviceSelector DeviceProvider ResourceFactory ResourceManager main #mermaid-svg-OcUYIx0PiAf4XHMw{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-OcUYIx0PiAf4XHMw .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-OcUYIx0PiAf4XHMw .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-OcUYIx0PiAf4XHMw .error-icon{fill:#552222;}#mermaid-svg-OcUYIx0PiAf4XHMw .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-OcUYIx0PiAf4XHMw .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-OcUYIx0PiAf4XHMw .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-OcUYIx0PiAf4XHMw .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-OcUYIx0PiAf4XHMw .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-OcUYIx0PiAf4XHMw .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-OcUYIx0PiAf4XHMw .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-OcUYIx0PiAf4XHMw .marker{fill:#333333;stroke:#333333;}#mermaid-svg-OcUYIx0PiAf4XHMw .marker.cross{stroke:#333333;}#mermaid-svg-OcUYIx0PiAf4XHMw svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-OcUYIx0PiAf4XHMw p{margin:0;}#mermaid-svg-OcUYIx0PiAf4XHMw .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-OcUYIx0PiAf4XHMw text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-OcUYIx0PiAf4XHMw .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-OcUYIx0PiAf4XHMw .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-OcUYIx0PiAf4XHMw .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-OcUYIx0PiAf4XHMw .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-OcUYIx0PiAf4XHMw #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-OcUYIx0PiAf4XHMw .sequenceNumber{fill:white;}#mermaid-svg-OcUYIx0PiAf4XHMw #sequencenumber{fill:#333;}#mermaid-svg-OcUYIx0PiAf4XHMw #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-OcUYIx0PiAf4XHMw .messageText{fill:#333;stroke:none;}#mermaid-svg-OcUYIx0PiAf4XHMw .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-OcUYIx0PiAf4XHMw .labelText,#mermaid-svg-OcUYIx0PiAf4XHMw .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-OcUYIx0PiAf4XHMw .loopText,#mermaid-svg-OcUYIx0PiAf4XHMw .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-OcUYIx0PiAf4XHMw .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-OcUYIx0PiAf4XHMw .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-OcUYIx0PiAf4XHMw .noteText,#mermaid-svg-OcUYIx0PiAf4XHMw .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-OcUYIx0PiAf4XHMw .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-OcUYIx0PiAf4XHMw .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-OcUYIx0PiAf4XHMw .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-OcUYIx0PiAf4XHMw .actorPopupMenu{position:absolute;}#mermaid-svg-OcUYIx0PiAf4XHMw .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-OcUYIx0PiAf4XHMw .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-OcUYIx0PiAf4XHMw .actor-man circle,#mermaid-svg-OcUYIx0PiAf4XHMw line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-OcUYIx0PiAf4XHMw :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 遍历PCI设备ClassID匹配+排除PF/默认路由 构建HostDevice组装InfoProvider链 loop每个ResourceConfig altPlugin Watch模式旧模式 loop每个ResourceServer newResourceManager(cliParams)NewResourceFactory(prefix, suffix, pluginWatch, useCdi)GetDeviceProvider(NetDeviceType) → NetDeviceProviderGetDeviceProvider(AcceleratorType) → AccelDeviceProviderGetDeviceProvider(AuxNetDeviceType) → AuxNetDeviceProviderreadConfig()os.ReadFile → json.Unmarshal → ResourceConfListGetDeviceFilter(config) → parseObjectOrSlice → SelectorObjsvalidConfigs()ValidResourceName + 资源名去重 + DeviceType验证 + DP.ValidConfigdiscoverHostDevices()AddTargetDevices(ghw.PCI.Devices, 0x02)initServers()GetDevices(config, selectorIndex)GetFilteredDevices(devices, config, selectorIndex)Filter × N (AND逻辑)excludeAllocatedDevicesGetResourcePool(config, filteredDevices)GetResourceServer(resourcePool)startAllServers()Start()Init() → CDI.CreateCDISpecForPool创建gRPC Server监听Unix SocketKubelet主动发现SocketRegister(版本,Socket,资源名)triggerUpdate goroutine (30s健康检查)
4.2 流程二:设备健康监控与状态更新
pkg/utils Kubelet updateCh ResourcePool ResourceServer 30s定时器 pkg/utils Kubelet updateCh ResourcePool ResourceServer 30s定时器 #mermaid-svg-MqPjSS49KH3Lm2Yb{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MqPjSS49KH3Lm2Yb .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MqPjSS49KH3Lm2Yb .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MqPjSS49KH3Lm2Yb .error-icon{fill:#552222;}#mermaid-svg-MqPjSS49KH3Lm2Yb .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MqPjSS49KH3Lm2Yb .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MqPjSS49KH3Lm2Yb .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MqPjSS49KH3Lm2Yb .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MqPjSS49KH3Lm2Yb .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MqPjSS49KH3Lm2Yb .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MqPjSS49KH3Lm2Yb .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MqPjSS49KH3Lm2Yb .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MqPjSS49KH3Lm2Yb .marker.cross{stroke:#333333;}#mermaid-svg-MqPjSS49KH3Lm2Yb svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MqPjSS49KH3Lm2Yb p{margin:0;}#mermaid-svg-MqPjSS49KH3Lm2Yb .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-MqPjSS49KH3Lm2Yb text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-MqPjSS49KH3Lm2Yb .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-MqPjSS49KH3Lm2Yb .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-MqPjSS49KH3Lm2Yb .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-MqPjSS49KH3Lm2Yb .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-MqPjSS49KH3Lm2Yb #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-MqPjSS49KH3Lm2Yb .sequenceNumber{fill:white;}#mermaid-svg-MqPjSS49KH3Lm2Yb #sequencenumber{fill:#333;}#mermaid-svg-MqPjSS49KH3Lm2Yb #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-MqPjSS49KH3Lm2Yb .messageText{fill:#333;stroke:none;}#mermaid-svg-MqPjSS49KH3Lm2Yb .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-MqPjSS49KH3Lm2Yb .labelText,#mermaid-svg-MqPjSS49KH3Lm2Yb .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-MqPjSS49KH3Lm2Yb .loopText,#mermaid-svg-MqPjSS49KH3Lm2Yb .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-MqPjSS49KH3Lm2Yb .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-MqPjSS49KH3Lm2Yb .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-MqPjSS49KH3Lm2Yb .noteText,#mermaid-svg-MqPjSS49KH3Lm2Yb .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-MqPjSS49KH3Lm2Yb .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-MqPjSS49KH3Lm2Yb .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-MqPjSS49KH3Lm2Yb .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-MqPjSS49KH3Lm2Yb .actorPopupMenu{position:absolute;}#mermaid-svg-MqPjSS49KH3Lm2Yb .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-MqPjSS49KH3Lm2Yb .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-MqPjSS49KH3Lm2Yb .actor-man circle,#mermaid-svg-MqPjSS49KH3Lm2Yb line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-MqPjSS49KH3Lm2Yb :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} altoperstate == "up"operstate != "up" loop每个设备 更新Node.Status.Allocatable调度器感知设备变化 loop每30秒 triggerUpdate tickProbe()IsNetlinkStatusUp(pciAddr)读取 /sys/bus/pci/devices/<addr>/net/*/operstatetrueapiDevicesid.Health = HealthyfalseapiDevicesid.Health = UnhealthyProbe完成updateCh <- GetDevices()ListAndWatch读取Send(ListAndWatchResponse{Devices})
健康状态影响:
| 设备状态 | operstate | Health值 | 调度行为 |
|---|---|---|---|
| 链路正常 | "up" | Healthy | 可调度,新Pod可请求 |
| 链路异常 | 非"up" | Unhealthy | 不可调度,已绑定Pod不受影响 |
| 设备移除 | 无operstate文件 | Unhealthy | 不可调度 |
4.3 流程三:设备分配(Allocate)
Container Runtime NadUtils CDI InfoProvider链 HostDevice ResourcePool ResourceServer Kubelet API Server Scheduler Container Runtime NadUtils CDI InfoProvider链 HostDevice ResourcePool ResourceServer Kubelet API Server Scheduler #mermaid-svg-R1GGWMLrgfHrYqBl{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-R1GGWMLrgfHrYqBl .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-R1GGWMLrgfHrYqBl .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-R1GGWMLrgfHrYqBl .error-icon{fill:#552222;}#mermaid-svg-R1GGWMLrgfHrYqBl .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-R1GGWMLrgfHrYqBl .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-R1GGWMLrgfHrYqBl .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-R1GGWMLrgfHrYqBl .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-R1GGWMLrgfHrYqBl .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-R1GGWMLrgfHrYqBl .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-R1GGWMLrgfHrYqBl .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-R1GGWMLrgfHrYqBl .marker{fill:#333333;stroke:#333333;}#mermaid-svg-R1GGWMLrgfHrYqBl .marker.cross{stroke:#333333;}#mermaid-svg-R1GGWMLrgfHrYqBl svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-R1GGWMLrgfHrYqBl p{margin:0;}#mermaid-svg-R1GGWMLrgfHrYqBl .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-R1GGWMLrgfHrYqBl text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-R1GGWMLrgfHrYqBl .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-R1GGWMLrgfHrYqBl .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-R1GGWMLrgfHrYqBl .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-R1GGWMLrgfHrYqBl .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-R1GGWMLrgfHrYqBl #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-R1GGWMLrgfHrYqBl .sequenceNumber{fill:white;}#mermaid-svg-R1GGWMLrgfHrYqBl #sequencenumber{fill:#333;}#mermaid-svg-R1GGWMLrgfHrYqBl #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-R1GGWMLrgfHrYqBl .messageText{fill:#333;stroke:none;}#mermaid-svg-R1GGWMLrgfHrYqBl .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-R1GGWMLrgfHrYqBl .labelText,#mermaid-svg-R1GGWMLrgfHrYqBl .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-R1GGWMLrgfHrYqBl .loopText,#mermaid-svg-R1GGWMLrgfHrYqBl .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-R1GGWMLrgfHrYqBl .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-R1GGWMLrgfHrYqBl .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-R1GGWMLrgfHrYqBl .noteText,#mermaid-svg-R1GGWMLrgfHrYqBl .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-R1GGWMLrgfHrYqBl .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-R1GGWMLrgfHrYqBl .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-R1GGWMLrgfHrYqBl .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-R1GGWMLrgfHrYqBl .actorPopupMenu{position:absolute;}#mermaid-svg-R1GGWMLrgfHrYqBl .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-R1GGWMLrgfHrYqBl .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-R1GGWMLrgfHrYqBl .actor-man circle,#mermaid-svg-R1GGWMLrgfHrYqBl line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-R1GGWMLrgfHrYqBl :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Pod调度阶段 容器创建阶段 loop每个InfoProvider loop每个deviceID loop每个InfoProvider loop每个deviceID altuseCdi模式 loop每个ContainerRequest 检查Node Allocatable ≥ Pod请求绑定Pod到NodeAllocate(ContainerRequests{DevicesIDs})GetDeviceSpecs(deviceIDs)GetDeviceSpecs()GetDeviceSpecs()DeviceSpec切片合并DeviceSpecs全部DeviceSpecsGetEnvs(prefix, deviceIDs)GetEnvVal()GetEnvVal()AdditionalInfo合并EnvVal格式化: PCIDEVICE_<PREFIX><NAME><KEY>全部EnvsGetMounts(deviceIDs)Mounts列表CreateContainerAnnotations(deviceIDs, prefix, kind)AnnotationKey: cdi.k8s.io/<prefix><kind>QualifiedName: <prefix>/<kind>/<deviceID>AnnotationsStoreDeviceInfoFile(prefix, deviceIDs)StoreDeviceInfoFile(dev, prefix, name)写入 /var/run/k8s.cni.cncf.io/devinfo/dpd/<prefix><name>/<id>AllocateResponse{ContainerResponses}CreateContainer(设备注入信息)创建设备文件 / 挂载 / 设置环境变量
五、输入输出分析
5.1 插件全局输入输出
| 输入 | 来源 | 格式 | 处理模块 |
|---|---|---|---|
| 配置文件 | /etc/pcidp/config.json | JSON | manager.readConfig |
| CLI 参数 | 命令行 | string/bool | main.flagInit |
| PCI 设备列表 | /sys/bus/pci/devices | sysfs | DeviceProvider.AddTargetDevices |
| 辅助设备列表 | /sys/bus/auxiliary/devices | sysfs | auxNetDeviceProvider.AddTargetDevices |
| 设备驱动 | /sys/bus/pci/.../driver | sysfs符号链接 | utils.GetDriverName |
| NUMA 节点 | /sys/bus/pci/.../numa_node | sysfs | utils.GetDevNode |
| 网络接口名 | /sys/bus/pci/.../net/ | sysfs | utils.GetNetNames |
| 链路状态 | /sys/bus/pci/.../net/*/operstate | sysfs | utils.IsNetlinkStatusUp |
| 链路属性 | netlink | netlink | NetlinkProvider.GetLinkAttrs |
| devlink 属性 | devlink | netlink | NetlinkProvider.GetDevLinkDeviceEswitchAttrs |
| RDMA 设备 | rdmamap | 库查询 | RdmaProvider.GetRdmaDevicesForPcidev |
| vDPA 设备 | govdpa | 库查询 | VdpaProvider.GetVdpaDeviceByPci |
| IB PKey | sriovnet | 库查询 | SriovnetProvider.GetDefaultPKeyFromPci |
| DDP 配置 | devlink info | netlink | utils.DevlinkGetDDPProfiles |
| 信号 | SIGHUP/SIGINT/SIGTERM/SIGQUIT | OS | main.sigCh |
| 输出 | 目标 | 格式 | 生成模块 |
|---|---|---|---|
| 设备注册 | Kubelet | gRPC Register | resourceServer.register |
| 设备列表 | Kubelet | gRPC ListAndWatchResponse | resourceServer.ListAndWatch |
| 设备分配 | Kubelet | gRPC AllocateResponse | resourceServer.Allocate |
| CDI Spec | /etc/cdi/sriov-dp-*.json | JSON | CDI.CreateCDISpecForPool |
| 设备信息文件 | /var/run/k8s.cni.cncf.io/devinfo/dpd/ | JSON | NadUtils.StoreDeviceInfoFile |
| Unix Socket | /var/lib/kubelet/plugins_registry/ | Unix域Socket | resourceServer.Start |
| 日志 | stderr | glog格式 | 全局 |
5.2 配置文件输入格式详解
json
{
"resourceList": [
{
"resourcePrefix": "intel.com",
"resourceName": "sriov_net",
"deviceType": "netDevice",
"excludeTopology": false,
"selectors": {
"vendors": ["8086"],
"devices": ["154c"],
"drivers": ["vfio-pci"],
"pciAddresses": ["0000:19:02.1"],
"pfNames": ["enp2s0f0#0-3"],
"rootDevices": ["0000:02:00.0"],
"linkTypes": ["ether"],
"isRdma": true,
"vdpaType": "vhost",
"needVhostNet": true,
"ddpProfiles": ["GTP*"],
"pKeys": ["0x8001"],
"acpiIndexes": ["1"]
},
"additionalInfo": {
"*": {"custom-key": "global-value"},
"0000:19:02.1": {"custom-key": "device-specific-value"}
}
},
{
"resourceName": "sriov_accel",
"deviceType": "accelerator",
"selectors": {
"vendors": ["8086"],
"devices": ["0b30"],
"drivers": ["vfio-pci"],
"pciAddresses": ["0000:af:00.0"]
}
},
{
"resourceName": "sriov_sf",
"deviceType": "auxNetDevice",
"selectors": {
"vendors": ["15b3"],
"drivers": ["mlx5_core"],
"auxTypes": ["sf"],
"linkTypes": ["ether"],
"isRdma": true,
"needVhostNet": true
}
}
]
}
5.3 AllocateResponse 输出格式详解
json
{
"containerResponses": [
{
"envs": {
"PCIDEVICE_INTEL_COM_SRIOV_NET_deviceID": "0000:19:02.1",
"PCIDEVICE_INTEL_COM_SRIOV_NET_mount": "/dev/vfio/vfio",
"PCIDEVICE_INTEL_COM_SRIOV_NET_dev-mount": "/dev/vfio/12",
"PCIDEVICE_INTEL_COM_SRIOV_NET_uverbs": "/dev/infiniband/uverbs0",
"PCIDEVICE_INTEL_COM_SRIOV_NET_rdma_dev": "mlx5_0",
"PCIDEVICE_INTEL_COM_SRIOV_NET_pfNetName": "enp2s0f0",
"PCIDEVICE_INTEL_COM_SRIOV_NET_netName": "enp2s0f0v1",
"PCIDEVICE_INTEL_COM_SRIOV_NET_linkType": "ether",
"PCIDEVICE_INTEL_COM_SRIOV_NET_linkSpeed": "10000"
},
"mounts": [],
"devices": [
{
"hostPath": "/dev/vfio/vfio",
"containerPath": "/dev/vfio/vfio",
"permissions": "rw"
},
{
"hostPath": "/dev/vfio/12",
"containerPath": "/dev/vfio/12",
"permissions": "rw"
},
{
"hostPath": "/dev/infiniband/uverbs0",
"containerPath": "/dev/infiniband/uverbs0",
"permissions": "rw"
},
{
"hostPath": "/dev/infiniband/rdma_cm",
"containerPath": "/dev/infiniband/rdma_cm",
"permissions": "rw"
}
],
"annotations": {
"cdi.k8s.io/intel_com_net": "intel.com/net/0000:19:02.1"
}
}
]
}
六、关键设计决策分析
6.1 设计决策一:工厂模式集中创建
决策 :所有组件(DeviceProvider、ResourcePool、ResourceServer、DeviceInfoProvider、DeviceSelector)的创建都通过 resourceFactory 集中管理。
优点:
- 依赖注入:调用者不需要知道具体实现类,只需依赖接口
- 可测试性:工厂方法可被替换为 Mock 工厂
- 一致性:所有组件的创建遵循相同的参数传递模式
- 解耦:模块之间通过接口和工厂交互,不直接依赖具体实现
缺点:
- 工厂类承担了过多职责(违反 SRP)
- 工厂方法数量多(~12个),代码量较大
#mermaid-svg-v4VVZZHJ4qoGqmpk{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-v4VVZZHJ4qoGqmpk .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-v4VVZZHJ4qoGqmpk .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-v4VVZZHJ4qoGqmpk .error-icon{fill:#552222;}#mermaid-svg-v4VVZZHJ4qoGqmpk .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-v4VVZZHJ4qoGqmpk .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-v4VVZZHJ4qoGqmpk .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-v4VVZZHJ4qoGqmpk .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-v4VVZZHJ4qoGqmpk .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-v4VVZZHJ4qoGqmpk .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-v4VVZZHJ4qoGqmpk .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-v4VVZZHJ4qoGqmpk .marker{fill:#333333;stroke:#333333;}#mermaid-svg-v4VVZZHJ4qoGqmpk .marker.cross{stroke:#333333;}#mermaid-svg-v4VVZZHJ4qoGqmpk svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-v4VVZZHJ4qoGqmpk p{margin:0;}#mermaid-svg-v4VVZZHJ4qoGqmpk .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-v4VVZZHJ4qoGqmpk .cluster-label text{fill:#333;}#mermaid-svg-v4VVZZHJ4qoGqmpk .cluster-label span{color:#333;}#mermaid-svg-v4VVZZHJ4qoGqmpk .cluster-label span p{background-color:transparent;}#mermaid-svg-v4VVZZHJ4qoGqmpk .label text,#mermaid-svg-v4VVZZHJ4qoGqmpk span{fill:#333;color:#333;}#mermaid-svg-v4VVZZHJ4qoGqmpk .node rect,#mermaid-svg-v4VVZZHJ4qoGqmpk .node circle,#mermaid-svg-v4VVZZHJ4qoGqmpk .node ellipse,#mermaid-svg-v4VVZZHJ4qoGqmpk .node polygon,#mermaid-svg-v4VVZZHJ4qoGqmpk .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-v4VVZZHJ4qoGqmpk .rough-node .label text,#mermaid-svg-v4VVZZHJ4qoGqmpk .node .label text,#mermaid-svg-v4VVZZHJ4qoGqmpk .image-shape .label,#mermaid-svg-v4VVZZHJ4qoGqmpk .icon-shape .label{text-anchor:middle;}#mermaid-svg-v4VVZZHJ4qoGqmpk .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-v4VVZZHJ4qoGqmpk .rough-node .label,#mermaid-svg-v4VVZZHJ4qoGqmpk .node .label,#mermaid-svg-v4VVZZHJ4qoGqmpk .image-shape .label,#mermaid-svg-v4VVZZHJ4qoGqmpk .icon-shape .label{text-align:center;}#mermaid-svg-v4VVZZHJ4qoGqmpk .node.clickable{cursor:pointer;}#mermaid-svg-v4VVZZHJ4qoGqmpk .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-v4VVZZHJ4qoGqmpk .arrowheadPath{fill:#333333;}#mermaid-svg-v4VVZZHJ4qoGqmpk .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-v4VVZZHJ4qoGqmpk .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-v4VVZZHJ4qoGqmpk .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-v4VVZZHJ4qoGqmpk .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-v4VVZZHJ4qoGqmpk .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-v4VVZZHJ4qoGqmpk .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-v4VVZZHJ4qoGqmpk .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-v4VVZZHJ4qoGqmpk .cluster text{fill:#333;}#mermaid-svg-v4VVZZHJ4qoGqmpk .cluster span{color:#333;}#mermaid-svg-v4VVZZHJ4qoGqmpk div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-v4VVZZHJ4qoGqmpk .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-v4VVZZHJ4qoGqmpk rect.text{fill:none;stroke-width:0;}#mermaid-svg-v4VVZZHJ4qoGqmpk .icon-shape,#mermaid-svg-v4VVZZHJ4qoGqmpk .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-v4VVZZHJ4qoGqmpk .icon-shape p,#mermaid-svg-v4VVZZHJ4qoGqmpk .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-v4VVZZHJ4qoGqmpk .icon-shape .label rect,#mermaid-svg-v4VVZZHJ4qoGqmpk .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-v4VVZZHJ4qoGqmpk .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-v4VVZZHJ4qoGqmpk .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-v4VVZZHJ4qoGqmpk :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 工厂模式
GetDeviceProvider
GetDeviceProvider
GetDeviceProvider
GetDefaultInfoProvider
GetSelector
GetResourcePool
GetResourceServer
GetRdmaSpec
GetVdpaDevice
GetDeviceFilter
GetNadUtils
resourceFactory
netDeviceProvider
accelDeviceProvider
auxNetDeviceProvider
DeviceInfoProvider链
12个Selector
3种ResourcePool
resourceServer
RdmaDeviceSpec
VdpaDeviceImpl
SelectorObjs
nadutils
6.2 设计决策二:装饰器模式构建设备
决策:使用 HostDeviceImpl → GenericPciDevice → GenericNetDevice → PciNetDevice 的装饰链构建设备对象。
优点:
- 渐进式增强:每层只添加自己关注的属性,职责清晰
- 接口隔离:不同使用者只需要关心自己需要的接口层
- 可组合性:AccelDevice 只需要 GenericPciDevice,不需要 GenericNetDevice
实现方式:
#mermaid-svg-cPZVLR79HOQ97Eoe{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-cPZVLR79HOQ97Eoe .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-cPZVLR79HOQ97Eoe .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-cPZVLR79HOQ97Eoe .error-icon{fill:#552222;}#mermaid-svg-cPZVLR79HOQ97Eoe .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-cPZVLR79HOQ97Eoe .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-cPZVLR79HOQ97Eoe .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-cPZVLR79HOQ97Eoe .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-cPZVLR79HOQ97Eoe .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-cPZVLR79HOQ97Eoe .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-cPZVLR79HOQ97Eoe .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-cPZVLR79HOQ97Eoe .marker{fill:#333333;stroke:#333333;}#mermaid-svg-cPZVLR79HOQ97Eoe .marker.cross{stroke:#333333;}#mermaid-svg-cPZVLR79HOQ97Eoe svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-cPZVLR79HOQ97Eoe p{margin:0;}#mermaid-svg-cPZVLR79HOQ97Eoe .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-cPZVLR79HOQ97Eoe .cluster-label text{fill:#333;}#mermaid-svg-cPZVLR79HOQ97Eoe .cluster-label span{color:#333;}#mermaid-svg-cPZVLR79HOQ97Eoe .cluster-label span p{background-color:transparent;}#mermaid-svg-cPZVLR79HOQ97Eoe .label text,#mermaid-svg-cPZVLR79HOQ97Eoe span{fill:#333;color:#333;}#mermaid-svg-cPZVLR79HOQ97Eoe .node rect,#mermaid-svg-cPZVLR79HOQ97Eoe .node circle,#mermaid-svg-cPZVLR79HOQ97Eoe .node ellipse,#mermaid-svg-cPZVLR79HOQ97Eoe .node polygon,#mermaid-svg-cPZVLR79HOQ97Eoe .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-cPZVLR79HOQ97Eoe .rough-node .label text,#mermaid-svg-cPZVLR79HOQ97Eoe .node .label text,#mermaid-svg-cPZVLR79HOQ97Eoe .image-shape .label,#mermaid-svg-cPZVLR79HOQ97Eoe .icon-shape .label{text-anchor:middle;}#mermaid-svg-cPZVLR79HOQ97Eoe .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-cPZVLR79HOQ97Eoe .rough-node .label,#mermaid-svg-cPZVLR79HOQ97Eoe .node .label,#mermaid-svg-cPZVLR79HOQ97Eoe .image-shape .label,#mermaid-svg-cPZVLR79HOQ97Eoe .icon-shape .label{text-align:center;}#mermaid-svg-cPZVLR79HOQ97Eoe .node.clickable{cursor:pointer;}#mermaid-svg-cPZVLR79HOQ97Eoe .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-cPZVLR79HOQ97Eoe .arrowheadPath{fill:#333333;}#mermaid-svg-cPZVLR79HOQ97Eoe .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-cPZVLR79HOQ97Eoe .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-cPZVLR79HOQ97Eoe .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cPZVLR79HOQ97Eoe .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-cPZVLR79HOQ97Eoe .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cPZVLR79HOQ97Eoe .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-cPZVLR79HOQ97Eoe .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-cPZVLR79HOQ97Eoe .cluster text{fill:#333;}#mermaid-svg-cPZVLR79HOQ97Eoe .cluster span{color:#333;}#mermaid-svg-cPZVLR79HOQ97Eoe div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-cPZVLR79HOQ97Eoe .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-cPZVLR79HOQ97Eoe rect.text{fill:none;stroke-width:0;}#mermaid-svg-cPZVLR79HOQ97Eoe .icon-shape,#mermaid-svg-cPZVLR79HOQ97Eoe .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cPZVLR79HOQ97Eoe .icon-shape p,#mermaid-svg-cPZVLR79HOQ97Eoe .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-cPZVLR79HOQ97Eoe .icon-shape .label rect,#mermaid-svg-cPZVLR79HOQ97Eoe .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cPZVLR79HOQ97Eoe .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-cPZVLR79HOQ97Eoe .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-cPZVLR79HOQ97Eoe :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 嵌入
嵌入
嵌入
嵌入
嵌入
嵌入
HostDeviceImpl
PCI基础+InfoProvider组合
GenericPciDevice
+pciAddr, acpiIndex
GenericNetDevice
+pfName, netName, linkType, rdmaSpec
PciNetDevice
+ddpProfiles, pKey, vdpaDev
AccelDevice
无额外属性
AuxNetDevice
+auxType, sfIndex
6.3 设计决策三:组合模式的 InfoProvider 链
决策:设备的信息(DeviceSpecs、EnvVal、Mounts)通过遍历 InfoProvider 链聚合生成,而非硬编码在设备类中。
优点:
- 开放-封闭原则:新增设备类型只需添加新 InfoProvider,无需修改设备基类
- 按需组合:根据配置动态决定注入哪些设备文件
- 细粒度控制:每个 InfoProvider 独立测试
组合示例:
| 设备场景 | InfoProvider 链 | 注入的设备文件 |
|---|---|---|
| VFIO 直通 | Generic → VFIO | /dev/vfio/vfio + /dev/vfio/N |
| VFIO + RDMA | Generic → VFIO → RDMA | /dev/vfio/* + /dev/infiniband/* |
| 内核驱动 + RDMA | Generic → RDMA | /dev/infiniband/* |
| UIO 直通 | Generic → UIO | /dev/uioX |
| vhost-vDPA | Generic → VFIO → VDPA | /dev/vfio/* + /dev/vhost-vdpa-N |
| virtio-vDPA | Generic → VDPA | (无设备文件) |
| vhost-net 共享 | Generic → VHOST | /dev/vhost-net + /dev/net/tun |
| 辅助设备+RDMA | Generic → RDMA → EXTRA | /dev/infiniband/* + 自定义env |
6.4 设计决策四:策略模式的设备选择器
决策:每个选择字段(vendors, drivers, pfNames 等)映射为一个独立的 DeviceSelector 实现,通过 AND 逻辑组合过滤。
优点:
- 策略模式:每个选择器是独立的过滤策略,可自由组合
- 可扩展性:新增选择字段只需新增 Selector 类 + Factory 方法
- 一致性:所有选择器遵循相同的 Filter(devices) → filteredDevices 接口
特殊设计:
IsRdma和VdpaType通过DriverSelector映射,避免了额外的选择器类型pfNames支持#VF范围语法,如enp2s0f0#1-3ddpProfiles支持 Glob 模式匹配
渲染错误: Mermaid 渲染失败: Parse error on line 12: ...DRV_ADDdrivers += "rdma" VDPA_ -----------------------^ Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND', 'PIPE', 'CYLINDEREND', 'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'STR'
6.5 设计决策五:Provider 抽象隔离设备类型差异
决策:通过 DeviceProvider 接口将三种设备类型(NetDevice、Accelerator、AuxNetDevice)的发现和构建逻辑隔离在独立子包中。
优点:
- 隔离变化:新增设备类型只需新增 Provider 子包
- 代码清晰:每种设备类型的逻辑自包含
- 独立测试:每种 Provider 可独立单元测试
差异矩阵:
| 能力 | NetDeviceProvider | AccelDeviceProvider | AuxNetDeviceProvider |
|---|---|---|---|
| 扫描源 | /sys/bus/pci | /sys/bus/pci | /sys/bus/auxiliary |
| Class过滤 | 0x02 | 0x12 | auxTypes字段 |
| PF排除 | ✅ | ❌ | N/A |
| 默认路由排除 | ✅ | ❌ | ❌ |
| RDMA支持 | ✅ | ❌ | ✅ |
| vDPA支持 | ✅ | ❌ | ❌ |
| NAD集成 | ✅ | ❌ | ✅ |
| NUMA拓扑 | ✅ | ✅ | ❌ |
| DDP配置 | ✅ | ❌ | ❌ |
| IB PKey | ✅ | ❌ | ❌ |
6.6 设计决策六:工具层 Provider 接口封装外部库
决策:对外部库(netlink、sriovnet、rdmamap、govdpa)的调用通过 Provider 接口封装,支持运行时替换(用于测试)。
go
// 全局变量 + Setter 注入
var netlinkProvider NetlinkProvider = &defaultNetlinkProvider{}
func SetNetlinkProviderInst(inst NetlinkProvider) { netlinkProvider = inst }
func GetNetlinkProvider() NetlinkProvider { return netlinkProvider }
优点:
- 可测试性:单元测试可注入 Mock Provider
- 解耦:业务逻辑不直接依赖外部库实现
- 灵活性:可替换为不同实现
Provider 接口一览:
| Provider | 封装库 | 核心方法 |
|---|---|---|
| NetlinkProvider | vishvananda/netlink | GetLinkAttrs, GetDevLinkDeviceEswitchAttrs, GetIPv4RouteList, GetDevlinkGetDeviceInfoByNameAsMap, HasRdmaParam |
| SriovnetProvider | k8snetworkplumbingwg/sriovnet | GetUplinkRepresentor, GetUplinkRepresentorFromAux, GetPfPciFromAux, GetSfIndexByAuxDev, GetNetDevicesFromAux, GetAuxNetDevicesFromPci, GetDefaultPKeyFromPci |
| RdmaProvider | Mellanox/rdmamap | GetRdmaDevicesForPcidev, GetRdmaDevicesForAuxdev, GetRdmaCharDevices |
| VdpaProvider | k8snetworkplumbingwg/govdpa | GetVdpaDeviceByPci |
七、核心数据流图
7.1 配置驱动数据流
渲染错误: Mermaid 渲染失败: Lexical error on line 3. Unrecognized text. ...tc/pcidp/config.json] end subgr -----------------------^
7.2 运行时数据流
渲染错误: Mermaid 渲染失败: Lexical error on line 9. Unrecognized text. ...us/pci/.../operstate] SYSFS --> -----------------------^
7.3 设备信息在容器内的注入
渲染错误: Mermaid 渲染失败: Lexical error on line 3. Unrecognized text. ... DEV1/dev/vfio/vfio VF -->|Dev -----------------------^
八、四种设备注入模式
8.1 模式对比
| 模式 | 驱动 | 设备文件 | 使用场景 |
|---|---|---|---|
| VFIO直通 | vfio-pci | /dev/vfio/vfio + /dev/vfio/N | DPDK 应用,用户态驱动 |
| UIO直通 | uio/igb_uio | /dev/uioX | 旧版 DPDK 应用 |
| 内核驱动 | i40evf/mlx5_core | (无特殊设备文件) | 普通网络应用,内核协议栈 |
| RDMA | 内核RDMA | /dev/infiniband/* | RDMA/RoCE 应用 |
| vDPA | vhost_vdpa/virtio_vdpa | /dev/vhost-vdpa-N 或无 | vDPA 硬件卸载 |
| vhost-net | 共享 | /dev/vhost-net + /dev/net/tun | OVS-DPDK vhost-user |
8.2 VFIO 直通模式数据流
VFIO InfoProvider ResourcePool ResourceServer Kubelet Container Runtime Pod (DPDK App) VFIO InfoProvider ResourcePool ResourceServer Kubelet Container Runtime Pod (DPDK App) #mermaid-svg-qyBSuglDIjD3inur{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-qyBSuglDIjD3inur .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-qyBSuglDIjD3inur .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-qyBSuglDIjD3inur .error-icon{fill:#552222;}#mermaid-svg-qyBSuglDIjD3inur .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-qyBSuglDIjD3inur .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-qyBSuglDIjD3inur .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-qyBSuglDIjD3inur .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-qyBSuglDIjD3inur .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-qyBSuglDIjD3inur .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-qyBSuglDIjD3inur .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-qyBSuglDIjD3inur .marker{fill:#333333;stroke:#333333;}#mermaid-svg-qyBSuglDIjD3inur .marker.cross{stroke:#333333;}#mermaid-svg-qyBSuglDIjD3inur svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-qyBSuglDIjD3inur p{margin:0;}#mermaid-svg-qyBSuglDIjD3inur .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-qyBSuglDIjD3inur text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-qyBSuglDIjD3inur .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-qyBSuglDIjD3inur .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-qyBSuglDIjD3inur .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-qyBSuglDIjD3inur .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-qyBSuglDIjD3inur #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-qyBSuglDIjD3inur .sequenceNumber{fill:white;}#mermaid-svg-qyBSuglDIjD3inur #sequencenumber{fill:#333;}#mermaid-svg-qyBSuglDIjD3inur #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-qyBSuglDIjD3inur .messageText{fill:#333;stroke:none;}#mermaid-svg-qyBSuglDIjD3inur .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-qyBSuglDIjD3inur .labelText,#mermaid-svg-qyBSuglDIjD3inur .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-qyBSuglDIjD3inur .loopText,#mermaid-svg-qyBSuglDIjD3inur .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-qyBSuglDIjD3inur .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-qyBSuglDIjD3inur .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-qyBSuglDIjD3inur .noteText,#mermaid-svg-qyBSuglDIjD3inur .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-qyBSuglDIjD3inur .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-qyBSuglDIjD3inur .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-qyBSuglDIjD3inur .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-qyBSuglDIjD3inur .actorPopupMenu{position:absolute;}#mermaid-svg-qyBSuglDIjD3inur .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-qyBSuglDIjD3inur .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-qyBSuglDIjD3inur .actor-man circle,#mermaid-svg-qyBSuglDIjD3inur line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-qyBSuglDIjD3inur :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} DPDK应用通过 /dev/vfio/12直接访问VF硬件 Allocate("0000:19:02.1")GetDeviceSpecs("0000:19:02.1")GetDeviceSpecs()/dev/vfio/vfio (IOMMU框架)/dev/vfio/12 (VF的IOMMU组)DeviceSpec{vfio}, DeviceSpec{vfio/12}DeviceSpecsGetEnvs("intel.com", "0000:19:02.1"){"PCIDEVICE_..._mount": "/dev/vfio/vfio", ...}AllocateResponseCreateContainer(specs + envs)容器启动,设备文件可用
8.3 RDMA 模式数据流
RdmaDeviceSpec RDMA InfoProvider ResourcePool ResourceServer Kubelet Container Runtime Pod (RDMA App) RdmaDeviceSpec RDMA InfoProvider ResourcePool ResourceServer Kubelet Container Runtime Pod (RDMA App) #mermaid-svg-gkYlLCY3M6KC4fgi{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-gkYlLCY3M6KC4fgi .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-gkYlLCY3M6KC4fgi .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-gkYlLCY3M6KC4fgi .error-icon{fill:#552222;}#mermaid-svg-gkYlLCY3M6KC4fgi .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-gkYlLCY3M6KC4fgi .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-gkYlLCY3M6KC4fgi .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-gkYlLCY3M6KC4fgi .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-gkYlLCY3M6KC4fgi .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-gkYlLCY3M6KC4fgi .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-gkYlLCY3M6KC4fgi .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-gkYlLCY3M6KC4fgi .marker{fill:#333333;stroke:#333333;}#mermaid-svg-gkYlLCY3M6KC4fgi .marker.cross{stroke:#333333;}#mermaid-svg-gkYlLCY3M6KC4fgi svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-gkYlLCY3M6KC4fgi p{margin:0;}#mermaid-svg-gkYlLCY3M6KC4fgi .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-gkYlLCY3M6KC4fgi text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-gkYlLCY3M6KC4fgi .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-gkYlLCY3M6KC4fgi .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-gkYlLCY3M6KC4fgi .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-gkYlLCY3M6KC4fgi .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-gkYlLCY3M6KC4fgi #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-gkYlLCY3M6KC4fgi .sequenceNumber{fill:white;}#mermaid-svg-gkYlLCY3M6KC4fgi #sequencenumber{fill:#333;}#mermaid-svg-gkYlLCY3M6KC4fgi #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-gkYlLCY3M6KC4fgi .messageText{fill:#333;stroke:none;}#mermaid-svg-gkYlLCY3M6KC4fgi .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-gkYlLCY3M6KC4fgi .labelText,#mermaid-svg-gkYlLCY3M6KC4fgi .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-gkYlLCY3M6KC4fgi .loopText,#mermaid-svg-gkYlLCY3M6KC4fgi .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-gkYlLCY3M6KC4fgi .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-gkYlLCY3M6KC4fgi .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-gkYlLCY3M6KC4fgi .noteText,#mermaid-svg-gkYlLCY3M6KC4fgi .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-gkYlLCY3M6KC4fgi .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-gkYlLCY3M6KC4fgi .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-gkYlLCY3M6KC4fgi .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-gkYlLCY3M6KC4fgi .actorPopupMenu{position:absolute;}#mermaid-svg-gkYlLCY3M6KC4fgi .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-gkYlLCY3M6KC4fgi .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-gkYlLCY3M6KC4fgi .actor-man circle,#mermaid-svg-gkYlLCY3M6KC4fgi line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-gkYlLCY3M6KC4fgi :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} rdmamap查询PCI → mlx5_0mlx5_0 → char devices RDMA应用使用 uverbs0进行用户态RDMA操作 Allocate("0000:19:02.1")GetDeviceSpecs("0000:19:02.1")GetDeviceSpecs()GetRdmaDeviceSpec()/dev/infiniband/uverbs0, /dev/infiniband/umad0, /dev/infiniband/issm0, /dev/infiniband/rdma_cmDeviceSpecsGetEnvVal()GetRdmaDeviceSpec() → 解析路径GetRdmaDeviceName() → "mlx5_0"{"uverbs": "/dev/infiniband/uverbs0", "rdma_dev": "mlx5_0", ...}DeviceSpecs + EnvsAllocateResponseCreateContainerRDMA设备文件可用
九、SR-IOV 插件在 Kubernetes 生态中的位置
9.1 与相关组件的交互
#mermaid-svg-GiTPQW576yDPZSC4{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-GiTPQW576yDPZSC4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-GiTPQW576yDPZSC4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-GiTPQW576yDPZSC4 .error-icon{fill:#552222;}#mermaid-svg-GiTPQW576yDPZSC4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-GiTPQW576yDPZSC4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-GiTPQW576yDPZSC4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-GiTPQW576yDPZSC4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-GiTPQW576yDPZSC4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-GiTPQW576yDPZSC4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-GiTPQW576yDPZSC4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-GiTPQW576yDPZSC4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-GiTPQW576yDPZSC4 .marker.cross{stroke:#333333;}#mermaid-svg-GiTPQW576yDPZSC4 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-GiTPQW576yDPZSC4 p{margin:0;}#mermaid-svg-GiTPQW576yDPZSC4 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-GiTPQW576yDPZSC4 .cluster-label text{fill:#333;}#mermaid-svg-GiTPQW576yDPZSC4 .cluster-label span{color:#333;}#mermaid-svg-GiTPQW576yDPZSC4 .cluster-label span p{background-color:transparent;}#mermaid-svg-GiTPQW576yDPZSC4 .label text,#mermaid-svg-GiTPQW576yDPZSC4 span{fill:#333;color:#333;}#mermaid-svg-GiTPQW576yDPZSC4 .node rect,#mermaid-svg-GiTPQW576yDPZSC4 .node circle,#mermaid-svg-GiTPQW576yDPZSC4 .node ellipse,#mermaid-svg-GiTPQW576yDPZSC4 .node polygon,#mermaid-svg-GiTPQW576yDPZSC4 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-GiTPQW576yDPZSC4 .rough-node .label text,#mermaid-svg-GiTPQW576yDPZSC4 .node .label text,#mermaid-svg-GiTPQW576yDPZSC4 .image-shape .label,#mermaid-svg-GiTPQW576yDPZSC4 .icon-shape .label{text-anchor:middle;}#mermaid-svg-GiTPQW576yDPZSC4 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-GiTPQW576yDPZSC4 .rough-node .label,#mermaid-svg-GiTPQW576yDPZSC4 .node .label,#mermaid-svg-GiTPQW576yDPZSC4 .image-shape .label,#mermaid-svg-GiTPQW576yDPZSC4 .icon-shape .label{text-align:center;}#mermaid-svg-GiTPQW576yDPZSC4 .node.clickable{cursor:pointer;}#mermaid-svg-GiTPQW576yDPZSC4 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-GiTPQW576yDPZSC4 .arrowheadPath{fill:#333333;}#mermaid-svg-GiTPQW576yDPZSC4 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-GiTPQW576yDPZSC4 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-GiTPQW576yDPZSC4 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-GiTPQW576yDPZSC4 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-GiTPQW576yDPZSC4 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-GiTPQW576yDPZSC4 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-GiTPQW576yDPZSC4 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-GiTPQW576yDPZSC4 .cluster text{fill:#333;}#mermaid-svg-GiTPQW576yDPZSC4 .cluster span{color:#333;}#mermaid-svg-GiTPQW576yDPZSC4 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-GiTPQW576yDPZSC4 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-GiTPQW576yDPZSC4 rect.text{fill:none;stroke-width:0;}#mermaid-svg-GiTPQW576yDPZSC4 .icon-shape,#mermaid-svg-GiTPQW576yDPZSC4 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-GiTPQW576yDPZSC4 .icon-shape p,#mermaid-svg-GiTPQW576yDPZSC4 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-GiTPQW576yDPZSC4 .icon-shape .label rect,#mermaid-svg-GiTPQW576yDPZSC4 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-GiTPQW576yDPZSC4 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-GiTPQW576yDPZSC4 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-GiTPQW576yDPZSC4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Pod
主机
Kubernetes集群
注册扩展资源
更新容量
调度决策
Allocate
创建容器
读取设备信息
调用
配置VF
配置VF
扫描
发现
发现
发现
管理
管理
管理
注入设备
注入设备
注入设备
API Server
Scheduler
Kubelet
Container Runtime
Multus CNI
sriov-cni
sriov-device-plugin
本项目
Network Policy
SR-IOV PF
VF 0
VF 1
VF N
sys/bus/pci
DPDK App
RDMA App
Kernel Net App
9.2 完整的 SR-IOV 工作流
#mermaid-svg-nyEA520ABdjEb2JC{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-nyEA520ABdjEb2JC .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-nyEA520ABdjEb2JC .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-nyEA520ABdjEb2JC .error-icon{fill:#552222;}#mermaid-svg-nyEA520ABdjEb2JC .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-nyEA520ABdjEb2JC .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-nyEA520ABdjEb2JC .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-nyEA520ABdjEb2JC .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-nyEA520ABdjEb2JC .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-nyEA520ABdjEb2JC .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-nyEA520ABdjEb2JC .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-nyEA520ABdjEb2JC .marker{fill:#333333;stroke:#333333;}#mermaid-svg-nyEA520ABdjEb2JC .marker.cross{stroke:#333333;}#mermaid-svg-nyEA520ABdjEb2JC svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-nyEA520ABdjEb2JC p{margin:0;}#mermaid-svg-nyEA520ABdjEb2JC .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-nyEA520ABdjEb2JC .cluster-label text{fill:#333;}#mermaid-svg-nyEA520ABdjEb2JC .cluster-label span{color:#333;}#mermaid-svg-nyEA520ABdjEb2JC .cluster-label span p{background-color:transparent;}#mermaid-svg-nyEA520ABdjEb2JC .label text,#mermaid-svg-nyEA520ABdjEb2JC span{fill:#333;color:#333;}#mermaid-svg-nyEA520ABdjEb2JC .node rect,#mermaid-svg-nyEA520ABdjEb2JC .node circle,#mermaid-svg-nyEA520ABdjEb2JC .node ellipse,#mermaid-svg-nyEA520ABdjEb2JC .node polygon,#mermaid-svg-nyEA520ABdjEb2JC .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-nyEA520ABdjEb2JC .rough-node .label text,#mermaid-svg-nyEA520ABdjEb2JC .node .label text,#mermaid-svg-nyEA520ABdjEb2JC .image-shape .label,#mermaid-svg-nyEA520ABdjEb2JC .icon-shape .label{text-anchor:middle;}#mermaid-svg-nyEA520ABdjEb2JC .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-nyEA520ABdjEb2JC .rough-node .label,#mermaid-svg-nyEA520ABdjEb2JC .node .label,#mermaid-svg-nyEA520ABdjEb2JC .image-shape .label,#mermaid-svg-nyEA520ABdjEb2JC .icon-shape .label{text-align:center;}#mermaid-svg-nyEA520ABdjEb2JC .node.clickable{cursor:pointer;}#mermaid-svg-nyEA520ABdjEb2JC .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-nyEA520ABdjEb2JC .arrowheadPath{fill:#333333;}#mermaid-svg-nyEA520ABdjEb2JC .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-nyEA520ABdjEb2JC .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-nyEA520ABdjEb2JC .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nyEA520ABdjEb2JC .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-nyEA520ABdjEb2JC .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nyEA520ABdjEb2JC .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-nyEA520ABdjEb2JC .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-nyEA520ABdjEb2JC .cluster text{fill:#333;}#mermaid-svg-nyEA520ABdjEb2JC .cluster span{color:#333;}#mermaid-svg-nyEA520ABdjEb2JC div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-nyEA520ABdjEb2JC .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-nyEA520ABdjEb2JC rect.text{fill:none;stroke-width:0;}#mermaid-svg-nyEA520ABdjEb2JC .icon-shape,#mermaid-svg-nyEA520ABdjEb2JC .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nyEA520ABdjEb2JC .icon-shape p,#mermaid-svg-nyEA520ABdjEb2JC .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-nyEA520ABdjEb2JC .icon-shape .label rect,#mermaid-svg-nyEA520ABdjEb2JC .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nyEA520ABdjEb2JC .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-nyEA520ABdjEb2JC .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-nyEA520ABdjEb2JC :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 6-应用运行
5-CNI配置
4-设备分配
3-Pod调度
2-插件发现与注册
1-管理员配置
设置SR-IOV VF数量
编写config.json
部署Device Plugin DaemonSet
扫描PCI设备
过滤匹配设备
创建资源池
注册到Kubelet
API Server更新Node容量
Pod请求intel.com/sriov_net
Scheduler检查容量
绑定Pod到Node
Kubelet调用Allocate
获取DeviceSpecs+Envs
运行时注入设备
Multus读取设备信息
sriov-cni配置VF
设置VF MAC/VLAN/IP
DPDK: 通过VFIO访问VF
RDMA: 通过uverbs访问
Kernel: 通过netdev访问
十、架构模式总结
10.1 使用的设计模式
| 模式 | 应用位置 | 解决的问题 |
|---|---|---|
| 工厂模式 | pkg/factory/resourceFactory | 集中创建所有组件,依赖注入 |
| 单例模式 | utils包的全局Provider | 全局共享外部库封装 |
| 装饰器模式 | HostDeviceImpl → GenericPciDevice → GenericNetDevice → PciNetDevice | 渐进式添加设备属性 |
| 组合模式 | InfoProvider链 | 灵活组合设备信息来源 |
| 策略模式 | 12个DeviceSelector | 可插拔的设备过滤策略 |
| 模板方法模式 | poolStub → netResourcePool/accelResourcePool/auxNetResourcePool | 共享通用逻辑,特化差异方法 |
| 观察者模式 | updateCh + ListAndWatch | 设备状态变化通知Kubelet |
| 接口隔离原则 | HostDevice/PciDevice/NetDevice/PciNetDevice/AccelDevice/AuxNetDevice | 不同角色只需关心所需接口 |
10.2 架构质量评价
| 维度 | 评分 | 说明 |
|---|---|---|
| 可扩展性 | ★★★★☆ | 新增设备类型/选择器/InfoProvider很容易,但新增设备发现源需修改Provider |
| 可测试性 | ★★★★★ | Provider接口全面Mock化,选择器独立测试,InfoProvider独立测试 |
| 可维护性 | ★★★★☆ | 模块划分清晰,职责单一,但factory过大 |
| 代码复用 | ★★★★☆ | poolStub共享逻辑,装饰器复用基类,但三个Provider有重复过滤代码 |
| 解耦度 | ★★★★★ | 接口驱动设计,模块间通过接口交互 |
| 性能 | ★★★☆☆ | 30s健康检查间隔,全量设备列表推送,对大规模场景可能不足 |
10.3 潜在改进方向
- 增量健康检查:当前 Probe() 检查所有设备,可改为只检查变化的设备
- 工厂拆分:resourceFactory 可拆分为 DeviceProviderFactory、SelectorFactory、InfoProviderFactory 等
- 配置热更新:当前 SIGHUP 信号仅停止服务,可支持配置热重载
- 设备缓存:对 sysfs 和 netlink 的查询结果可缓存,减少 I/O 开销
- 辅助设备NUMA支持:当前 AuxNetDevice 不支持 NUMA 拓扑
十一、代码行数统计
| 包 | 文件数 | 估计行数 | 占比 |
|---|---|---|---|
| cmd/sriovdp/ | 2 | 350 | 7% |
| pkg/types/ | 1 | 380 | 8% |
| pkg/factory/ | 1 | 300 | 6% |
| pkg/devices/ | 6 | 600 | 13% |
| pkg/infoprovider/ | 7 | 430 | 9% |
| pkg/netdevice/ | 4 | 630 | 13% |
| pkg/accelerator/ | 3 | 200 | 4% |
| pkg/auxnetdevice/ | 3 | 340 | 7% |
| pkg/resources/ | 3 | 760 | 16% |
| pkg/cdi/ | 1 | 120 | 3% |
| pkg/utils/ | 5 | 740 | 15% |
| 总计 | 36 | ~4850 | 100% |
十二、关键函数索引
| 函数 | 文件 | 核心职责 |
|---|---|---|
| main | cmd/sriovdp/main.go | 程序入口,编排生命周期 |
| newResourceManager | cmd/sriovdp/manager.go | 创建资源管理器 |
| readConfig | cmd/sriovdp/manager.go | 读取并解析配置文件 |
| validConfigs | cmd/sriovdp/manager.go | 验证配置合法性 |
| discoverHostDevices | cmd/sriovdp/manager.go | 扫描主机PCI设备 |
| initServers | cmd/sriovdp/manager.go | 创建资源服务器 |
| startAllServers | cmd/sriovdp/manager.go | 启动所有gRPC服务器 |
| AddTargetDevices | pkg/netdevice/netDeviceProvider.go | PCI设备发现与过滤 |
| GetDevices | pkg/netdevice/netDeviceProvider.go | 构建HostDevice实例 |
| GetFilteredDevices | pkg/netdevice/netDeviceProvider.go | 应用选择器过滤设备 |
| NewHostDeviceImpl | pkg/devices/host.go | 创建设备基类 |
| NewGenericNetDevice | pkg/devices/gen_net.go | 装饰网络属性 |
| NewGenericPciDevice | pkg/devices/gen_pci.go | 装饰PCI属性 |
| NewPciNetDevice | pkg/netdevice/pciNetDevice.go | 组装完整网络设备 |
| NewRdmaDeviceSpec | pkg/devices/rdma.go | 创建RDMA规范 |
| NewVdpaDeviceImpl | pkg/devices/vdpa.go | 创建vDPA设备 |
| GetDeviceSpecs | pkg/devices/host.go | 聚合InfoProvider的DeviceSpecs |
| GetEnvVal | pkg/devices/host.go | 聚合InfoProvider的环境变量 |
| NewNetResourcePool | pkg/netdevice/netResourcePool.go | 创建网络资源池 |
| NewResourceServer | pkg/resources/server.go | 创建gRPC服务器 |
| Start | pkg/resources/server.go | 启动gRPC服务 |
| ListAndWatch | pkg/resources/server.go | 流式设备列表推送 |
| Allocate | pkg/resources/server.go | 设备分配 |
| triggerUpdate | pkg/resources/server.go | 定时健康检查 |
| Filter | pkg/resources/deviceSelectors.go (×12) | 各类设备过滤 |
| CreateCDISpecForPool | pkg/cdi/cdi.go | 生成CDI规范文件 |
| CreateContainerAnnotations | pkg/cdi/cdi.go | 生成CDI容器注解 |
| StoreDeviceInfoFile | pkg/netdevice/nadutils.go | 存储NAD设备信息 |
| GetDefaultInfoProvider | pkg/factory/factory.go | 创建InfoProvider链 |
| GetDeviceFilter | pkg/factory/factory.go | 解析选择器配置 |
| FilterBySelector | pkg/factory/factory.go | 应用选择器 |