首页
关于
Search
1
PacketForge 博客部署文档
16 阅读
2
深入 SONiC 与 SAI:从命令行到芯片的完整数据之旅
14 阅读
3
DPU 与 CPO:AI 时代的网络基础设施革命
11 阅读
4
Broadcom芯片
10 阅读
5
DPDK高性能网络
10 阅读
默认分类
交换芯片
高性能网络
AI算力网络
WebSocket高性能项目
DPDK 成长路线
①性能工程基础
②DPDK 源码深读
③用户态协议栈
④软件交换与 SONiC
⑤PCIe、虚拟化与 DPU
⑥面试与复盘
登录
Search
标签搜索
DPDK→DPU 学习路线
P0
P1
P2
P3
P5
PCIe
P4
P6
libmtcp
NUMA
mTCP
OVS
SONiC
SAI
DPU
perf
gdb
EAL
mempool
PacketForge
累计撰写
53
篇文章
累计收到
3
条评论
首页
栏目
页面
关于
最新文章
热门文章
评论最多
点赞最多
2026-08-18
P5-04 · vDPA 框架:把 virtqueue 卸载进硬件,guest 零感知
对应路线图:Phase 5 (Day 141-168) | DPDK 24.11.6 LTS | 内核对照 v6.6代码出处:source/linux-stable/drivers/vdpa/vdpa.c、drivers/virtio/virtio_vdpa.c、source/dpdk-stable-24.11.6/lib/vhost/vdpa.c上一篇:P5-03 virtio 与 vhost-user | 下一篇:P5-05 rte_flow offload 实测一句话定位vhost-user 把后端搬到用户态,性能还是受限于"每包过一遍 CPU"。vDPA 更进一步:virtqueue 的收发数据面整个下沉到 SmartNIC/DPU 硬件,guest 里还是那个标准 virtio-net 驱动,什么都不用改。控制面仍走标准接口(vDPA bus + vhost-vdpa / DPDK rte_vdpa),数据面走硬件——"协议不变,执行者变了"。内核 vDPA 框架:一个 bus,一套 ops① 设备注册入口:vdpa_register_device(drivers/vdpa/vdpa.c:265-274)int vdpa_register_device(struct vdpa_device *vdev, u32 nvqs) { int err; down_write(&vdpa_dev_lock); err = __vdpa_register_device(vdev, nvqs); up_write(&vdpa_dev_lock); return err; }vDPA 设备是一个虚拟 bus 上的设备(vdpa_bus):厂商驱动(比如 drivers/vdpa/mlx5/net/mlx5_vnet.c)probe 到硬件后,分配 vdpa_device 并在这里注册(doc 注释 :257-264 明确"先调 vdpa_alloc_device 再注册")。设备的能力全部通过 vdpa_config_ops 虚表暴露——get_features、set_vq_state、get_vq_state、kick_vq 等(struct 定义在 include/linux/vdpa.h,本阶段未逐行读)。总线负责对接,ops 负责翻译成硬件操作。② 把 vDPA 设备变成 virtio 设备:virtio_vdpa_probe(drivers/virtio/virtio_vdpa.c:489-526)static int virtio_vdpa_probe(struct vdpa_device *vdpa) { const struct vdpa_config_ops *ops = vdpa->config; struct virtio_vdpa_device *vd_dev, *reg_dev = NULL; int ret = -EINVAL; vd_dev = kzalloc(sizeof(*vd_dev), GFP_KERNEL); if (!vd_dev) return -ENOMEM; // ...省略 dev/ops/锁初始化 ... vd_dev->vdev.id.device = ops->get_device_id(vdpa); if (vd_dev->vdev.id.device == 0) goto err; vd_dev->vdev.id.vendor = ops->get_vendor_id(vdpa); ret = register_virtio_device(&vd_dev->vdev); reg_dev = vd_dev; if (ret) goto err; vdpa_set_drvdata(vdpa, vd_dev); return 0; }这一步是整个 vDPA 的点睛之笔:从 vDPA 设备读出 virtio 设备 ID(:506),用 register_virtio_device(:511)把它注册成标准 virtio 设备。内核的 virtio 核心一看到它,就会让 guest 侧的 virtio-net 驱动去 probe——guest 完全以为自己在跟一个软件后端说话。驱动结构在 :535-543:.probe = virtio_vdpa_probe,module_vdpa_driver(virtio_vdpa_driver) 注册到 vDPA bus。数据面上,guest 的 kick 经过 ops 的 kick_vq 变成"告诉硬件队列有活干";硬件收发包直接 DMA 读写 guest 的 ring,CPU 只处理控制面。DPDK 侧:rte_vdpa 让 vhost-user 应用无感接硬件③ 注册与强制接口检查(lib/vhost/vdpa.c:74-124,节选)struct rte_vdpa_device * rte_vdpa_register_device(struct rte_device *rte_dev, struct rte_vdpa_dev_ops *ops) { struct rte_vdpa_device *dev; int ret = 0; if (ops == NULL) return NULL; /* Check mandatory ops are implemented */ if (!ops->get_queue_num || !ops->get_features || !ops->get_protocol_features || !ops->dev_conf || !ops->dev_close || !ops->set_vring_state || !ops->set_features) { VHOST_CONFIG_LOG(rte_dev->name, ERR, "Some mandatory vDPA ops aren't implemented"); return NULL; } // ...省略重复注册检查、分配、type 获取 ... TAILQ_INSERT_TAIL(vdpa_device_list, dev, next); // ...对外接口是 vhost-user 协议,对内接口是这 7 个强制 ops——DPDK 应用(testpmd/OVS)不用改一行代码,vDPA 驱动在协议层把 SET_VRING_NUM/SET_FEATURES 等消息翻译成硬件配置。这份设计让"软件 vhost-user 后端"和"硬件 vDPA 后端"可以互换。④ used ring 回填:硬件算完,框架负责"交作业"(lib/vhost/vdpa.c:150-182,节选)int rte_vdpa_relay_vring_used(int vid, uint16_t qid, void *vring_m) { // ...省略空指针/队列号/packed 检查 ... s_vring = (struct vring *)vring_m; vq = dev->virtqueue[qid]; idx = vq->used->idx; idx_m = s_vring->used->idx; ret = (uint16_t)(idx_m - idx); vq->used->flags = s_vring->used->flags; while (idx != idx_m) { /* copy used entry, used ring logging is not covered here */ vq->used->ring[idx & (vq->size - 1)] = s_vring->used->ring[idx & (vq->size - 1)]; desc_id = vq->used->ring[idx & (vq->size - 1)].id; desc_ring = vq->desc; nr_descs = vq->size; // ...省略 indirect 描述符处理 ...硬件收完包后写的是自己的 shadow ring(s_vring),框架把这个"成绩单"逐条拷回 guest 的 used ring(:179-182)——硬件不必知道 guest 内存布局,框架兜住协议兼容性。这是 vDPA 数据面最后 1% 的关键设计。🐧 内核对照:内核 vhost-vdpa vs DPDK rte_vdpa维度内核 vhost-vdpaDPDK rte_vdpa控制面接口vDPA bus 原生接口(vdpa.c:265)vhost-user 协议桥接(vdpa.c:74)对接方virtio_vdpa(virtio_vdpa.c:511)注册标准 virtio 设备应用侧仍是 vhost-user fd/消息数据面硬件直操作 guest ring硬件 shadow ring + relay 回填(vdpa.c:150)典型用户KVM + SmartNIC 直通OVS-DPDK 云网络卸载两边都遵守同一个原则:数据面下沉硬件,控制面留在通用层。内核版从 virtio 生态接入,DPDK 版从 vhost-user 生态接入——殊途同归。面试 3 问vDPA 与 SR-IOV 直通有什么本质区别? → SR-IOV 里 guest 用厂商专用驱动(如 iavf)感知真实硬件;vDPA 里 guest 用标准 virtio 驱动,硬件细节被 vDPA 层完全隐藏——迁移、升级、换硬件都不动 guest。为什么 virtio_vdpa_probe 要读 get_device_id? → vDPA 设备要先"伪装"成对应类型的 virtio 设备(virtio_vdpa.c:506-511),内核 virtio 核心才会让 guest 驱动正确 probe;device id 为 0 视为无效直接失败(:507-508)。硬件的 shadow ring 是什么,为什么要 relay? → 硬件在自己的内存里维护处理结果,不直接写 guest 的 used ring;rte_vdpa_relay_vring_used 把 used 条目批量拷回 guest ring(vdpa.c:179-182),隔离硬件实现与协议内存布局。🔧 动手实验J3455 没有 vDPA 硬件(mlx5_vdpa 需要 ConnectX SmartNIC),用内核自带的模拟器 vdpa_sim 走通框架:# 1. 加载模拟设备(drivers/vdpa/vdpa_sim/vdpa_sim_net.c, # mgmtdev 名字 "vdpasim_net" 见 :443) modprobe vdpa_sim_net ls /sys/bus/vdpa/devices/ # 期望看到 vdpa0 之类 # 2. 用 iproute2 的 vdpa 工具创建 mgmtdev / 设备 vdpa mgmtdev show vdpa dev add name vdpa0 mgmtdev vdpasim_net # 3. QEMU 用 vhost-vdpa 启动 guest qemu-system-x86_64 -netdev vhost-vdpa,id=n1,vhostdev=/dev/vhost-vdpa-0 ... # 4. 抓取关键路径证据:guest 内 dmesg 确认 probe 到 virtio_net # host 侧对比 vhost-net / vhost-vdpa / vhost-user 三种后端 iperf3数据落点:perf-data/P5/04-vdpa-sim.md(vdpa_sim 拓扑截图、三种后端吞吐对比、guest dmesg 中 virtio_net probe 日志)。模拟器没有性能意义,价值在于把注册/probe/数据面 relay 这条链路完整走一遍。下一篇:P5-05 · rte_flow offload 实测:SW vs HW 路径对比
2026年08月18日
0 阅读
0 评论
0 点赞
第 1/1 页 · 本页 1 条 · 共 1 条