0. 引言
因为手上一个项目是网卡模拟器, 因此需要在rx_ring, tx_ring中写东西模拟网卡的收发功能。之前尝试使用物理地址完全解耦, 但是发现该种方案需要大量映射, 性能很差, 大概是发包仪的 1/2。遂采用主从进程的方式直接对上层设备句柄进行操作来模拟。
1. dpdk 主从进程实现原理
如上图所示, 所有的dpdk程序都会使用hugepage作为存储全局变量的位置。这意味着在primary进程所使用的全局变量在secondary可以直接获取。这就是主从进程实现共享变量的原理。
2. 驱动层从进程的支持
每次启动dpdk程序, dpdk对设备进行探测, 这里以vdev
为例。
vdev.c
dpdk启动时会对vdev进行一次探测
static int
vdev_probe_all_drivers(struct rte_vdev_device *dev)
{
...
name = rte_vdev_device_name(dev);
VDEV_LOG(DEBUG, "Search driver to probe device %s", name);
if (vdev_parse(name, &driver))
return -1;
ret = driver->probe(dev);
...
}
在driver层中
static struct rte_vdev_driver driver = {
.probe = rte_pmd_probe,
.remove = rte_pmd_remove,
};
static int rte_pmd_probe(struct rte_vdev_device *vdev)
{
...
/*secondary process probe*/
const char *vdev_name = rte_vdev_device_name(vdev);
if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
eth_dev = rte_eth_dev_attach_secondary(vdev_name); // 从进程只需要获取
if (!eth_dev) {
MACB_LOG(ERR, "Secondary failed to probe eth_dev.");
return -1;
}
if (vdev->device.numa_node == SOCKET_ID_ANY)
vdev->device.numa_node = rte_socket_id();
eth_dev->device = &vdev->device;
rte_eth_dev_probing_finish(eth_dev);
device_create... // 主进程将创建该设备
return 0;
}
...
}
在probe函数中, 判断是否为从进程, 如果是从进程, 则尝试从主进程那里获取对应的eth_dev
句柄 而非再次从后头创建设备。最后再调用rte_eth_dev_probing_finish
新建一个事件, 告诉dpdk拿到了该设备。至此, 从进程可以通过全局变量去找到这个设备了。