[dpdk] dpdk编译成动态库使用 -- PCI port自动发现与pmd动态加载
1. 修改配置文件 .conf, 设置如下变量的值.
[root@D129 x86_64-native-linuxapp-gcc]# cat dpdk/x86_64-native-linuxapp-gcc/.config |grep SHARE
CONFIG_RTE_BUILD_SHARED_LIB=y
2. 这个时候, 再编译的 dpdk app就会自动链接dpdk的动态库. 如下:
[root@D129 app]# ldd testpmd linux-vdso.so.1 => (0x00007ffed89fd000) librte_kni.so.2 => /root/Src/copyright/j/dpdk/x86_64-native-linuxapp-gcc/lib/librte_kni.so.2 (0x00007fe9c983f000) librte_pipeline.so.3 => /root/Src/copyright/j/dpdk/x86_64-native-linuxapp-gcc/lib/librte_pipeline.so.3 (0x00007fe9c962b000) librte_table.so.2 => /root/Src/copyright/j/dpdk/x86_64-native-linuxapp-gcc/lib/librte_table.so.2 (0x00007fe9c93ed000) librte_port.so.3 => /root/Src/copyright/j/dpdk/x86_64-native-linuxapp-gcc/lib/librte_port.so.3 (0x00007fe9c9191000) librte_pdump.so.1 => /root/Src/copyright/j/dpdk/x86_64-native-linuxapp-gcc/lib/librte_pdump.so.1 (0x00007fe9c8d77000) librte_distributor.so.1 => /root/Src/copyright/j/dpdk/x86_64-native-linuxapp-gcc/lib/librte_distributor.so.1 (0x00007fe9c8b74000) librte_reorder.so.1 => /root/Src/copyright/j/dpdk/x86_64-native-linuxapp-gcc/lib/librte_reorder.so.1 (0x00007fe9c8965000) librte_ip_frag.so.1 => /root/Src/copyright/j/dpdk/x86_64-native-linuxapp-gcc/lib/librte_ip_frag.so.1 (0x00007fe9c8724000) librte_meter.so.1 => /root/Src/copyright/j/dpdk/x86_64-native-linuxapp-gcc/lib/librte_meter.so.1 (0x00007fe9c8521000) librte_sched.so.1 => /root/Src/copyright/j/dpdk/x86_64-native-linuxapp-gcc/lib/librte_sched.so.1 (0x00007fe9c830d000) librte_lpm.so.2 => /root/Src/copyright/j/dpdk/x86_64-native-linuxapp-gcc/lib/librte_lpm.so.2 (0x00007fe9c80ff000) librte_acl.so.2 => /root/Src/copyright/j/dpdk/x86_64-native-linuxapp-gcc/lib/librte_acl.so.2 (0x00007fe9c7ee5000) librte_jobstats.so.1 => /root/Src/copyright/j/dpdk/x86_64-native-linuxapp-gcc/lib/librte_jobstats.so.1 (0x00007fe9c7ce2000) librte_power.so.1 => /root/Src/copyright/j/dpdk/x86_64-native-linuxapp-gcc/lib/librte_power.so.1 (0x00007fe9c7acd000) librte_timer.so.1 => /root/Src/copyright/j/dpdk/x86_64-native-linuxapp-gcc/lib/librte_timer.so.1 (0x00007fe9c78c3000) librte_hash.so.2 => /root/Src/copyright/j/dpdk/x86_64-native-linuxapp-gcc/lib/librte_hash.so.2 (0x00007fe9c76af000) librte_vhost.so.3 => /root/Src/copyright/j/dpdk/x86_64-native-linuxapp-gcc/lib/librte_vhost.so.3 (0x00007fe9c7477000) librte_kvargs.so.1 => /root/Src/copyright/j/dpdk/x86_64-native-linuxapp-gcc/lib/librte_kvargs.so.1 (0x00007fe9c7274000) librte_mbuf.so.2 => /root/Src/copyright/j/dpdk/x86_64-native-linuxapp-gcc/lib/librte_mbuf.so.2 (0x00007fe9c7071000) libethdev.so.4 => /root/Src/copyright/j/dpdk/x86_64-native-linuxapp-gcc/lib/libethdev.so.4 (0x00007fe9c6dd6000) librte_cryptodev.so.1 => /root/Src/copyright/j/dpdk/x86_64-native-linuxapp-gcc/lib/librte_cryptodev.so.1 (0x00007fe9c6bc1000) librte_mempool.so.2 => /root/Src/copyright/j/dpdk/x86_64-native-linuxapp-gcc/lib/librte_mempool.so.2 (0x00007fe9c69b9000) librte_ring.so.1 => /root/Src/copyright/j/dpdk/x86_64-native-linuxapp-gcc/lib/librte_ring.so.1 (0x00007fe9c67b5000) librte_eal.so.2 => /root/Src/copyright/j/dpdk/x86_64-native-linuxapp-gcc/lib/librte_eal.so.2 (0x00007fe9c6546000) librte_cmdline.so.2 => /root/Src/copyright/j/dpdk/x86_64-native-linuxapp-gcc/lib/librte_cmdline.so.2 (0x00007fe9c633b000) librte_cfgfile.so.2 => /root/Src/copyright/j/dpdk/x86_64-native-linuxapp-gcc/lib/librte_cfgfile.so.2 (0x00007fe9c6137000) librte_pmd_bond.so.1 => /root/Src/copyright/j/dpdk/x86_64-native-linuxapp-gcc/lib/librte_pmd_bond.so.1 (0x00007fe9c5efa000) libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fe9c5cd9000) libdl.so.2 => /lib64/libdl.so.2 (0x00007fe9c5ad4000) libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fe9c58b8000) libc.so.6 => /lib64/libc.so.6 (0x00007fe9c54f5000) /lib64/ld-linux-x86-64.so.2 (0x00007fe9c9a51000) libm.so.6 => /lib64/libm.so.6 (0x00007fe9c51f2000) librt.so.1 => /lib64/librt.so.1 (0x00007fe9c4fea000) [root@D129 app]#
3. 但是与static的时候对比, 你会发现有如下的问题:
用static链接的时候, rte_init的时候,会扫描所有的PCI设备,找到所有可用的port, 如下:
[root@D129 app]# ./testpmd EAL: Detected 16 lcore(s) EAL: Probing VFIO support... EAL: WARNING: cpu flags constant_tsc=yes nonstop_tsc=no -> using unreliable clock cycles ! EAL: PCI device 0000:00:03.0 on NUMA socket -1 EAL: probe driver: 1af4:1000 rte_virtio_pmd EAL: PCI device 0000:00:04.0 on NUMA socket -1 EAL: probe driver: 1af4:1000 rte_virtio_pmd USER1: create a new mbuf pool <mbuf_pool_socket_0>: n=267456, size=2304, socket=0 RING: Cannot reserve memory EAL: Error - exiting with code: 1 Cause: Creation of mbuf pool for socket 0 failed: Cannot allocate memory [root@D129 app]#
在使用shared so库的时候, 会发现,dpdk app扫描不到任何 PCI 设备了. 如下:
[root@D129 app]# ./testpmd EAL: Detected 16 lcore(s) EAL: Probing VFIO support... EAL: WARNING: cpu flags constant_tsc=yes nonstop_tsc=no -> using unreliable clock cycles ! EAL: No probed ethernet devices USER1: create a new mbuf pool <mbuf_pool_socket_0>: n=267456, size=2304, socket=0 RING: Cannot reserve memory EAL: Error - exiting with code: 1 Cause: Creation of mbuf pool for socket 0 failed: Cannot allocate memory
这个时候,我们ldd app,会发现, 它并没有ld到pmd的so,
[root@D129 app]# ldd testpmd |grep pmd librte_pmd_bond.so.1 => /root/Src/copyright/j/dpdk/x86_64-native-linuxapp-gcc/lib/librte_pmd_bond.so.1 (0x00007fa25689a000) [root@D129 app]#
猜测, dpdk在shared的情况下, pmd的库,是需要动态加载的. 并找到如下参数:
[root@D129 app]# ./testpmd -h |grep -A1 LIB.so -d LIB.so|DIR Add a driver or driver directory (can be used multiple times)
使用 -d 参数制定 virtio的so, (我的虚拟机是virtio的网络设备), 果然生效了
[root@D129 app]# ./testpmd -d ../lib/librte_pmd_virtio.so EAL: Detected 16 lcore(s) EAL: Probing VFIO support... EAL: WARNING: cpu flags constant_tsc=yes nonstop_tsc=no -> using unreliable clock cycles ! EAL: PCI device 0000:00:03.0 on NUMA socket -1 EAL: probe driver: 1af4:1000 rte_virtio_pmd EAL: PCI device 0000:00:04.0 on NUMA socket -1 EAL: probe driver: 1af4:1000 rte_virtio_pmd USER1: create a new mbuf pool <mbuf_pool_socket_0>: n=267456, size=2304, socket=0 RING: Cannot reserve memory EAL: Error - exiting with code: 1 Cause: Creation of mbuf pool for socket 0 failed: Cannot allocate memory [root@D129 app]#
4. 问题分析
参考 dpdk 的源码 ../dpdk/lib/librte_eal/common/eal_common_options.c::eal_plugins_init()
在读取 -d 参数的同时, dpdk在 rte_init函数中还会读取 RTE_EAL_PMD_PATH 目录下的文件, 所有读到的文件会使用 dlopen() 打开. 详细逻辑参见代码.
变量RTE_EAL_PMD_PATH的值由CONFIG_RTE_EAL_PMD_PATH在编译的时候决定.
5. 参考redhat的rpm spec, 最终的解决方案是这样的.
5.1 生成一个编译与运行时都存在的目录: /lib64/tong-dpdk-pmds/,
5.2 将所以pmd软链接到这个目录下
[root@D129 app]# ll /lib64/tong-dpdk-pmds/ total 0 lrwxrwxrwx 1 root root 28 Jul 25 13:37 librte_pmd_af_packet.so.1 -> ../librte_pmd_af_packet.so.1 lrwxrwxrwx 1 root root 23 Jul 25 13:37 librte_pmd_bnxt.so.1 -> ../librte_pmd_bnxt.so.1 lrwxrwxrwx 1 root root 23 Jul 25 13:37 librte_pmd_bond.so.1 -> ../librte_pmd_bond.so.1 lrwxrwxrwx 1 root root 24 Jul 25 13:37 librte_pmd_cxgbe.so.1 -> ../librte_pmd_cxgbe.so.1 lrwxrwxrwx 1 root root 24 Jul 25 13:37 librte_pmd_e1000.so.1 -> ../librte_pmd_e1000.so.1 lrwxrwxrwx 1 root root 22 Jul 25 13:37 librte_pmd_ena.so.1 -> ../librte_pmd_ena.so.1 lrwxrwxrwx 1 root root 23 Jul 25 13:37 librte_pmd_enic.so.1 -> ../librte_pmd_enic.so.1 lrwxrwxrwx 1 root root 24 Jul 25 13:37 librte_pmd_fm10k.so.1 -> ../librte_pmd_fm10k.so.1 lrwxrwxrwx 1 root root 23 Jul 25 13:37 librte_pmd_i40e.so.1 -> ../librte_pmd_i40e.so.1 lrwxrwxrwx 1 root root 24 Jul 25 13:37 librte_pmd_ixgbe.so.1 -> ../librte_pmd_ixgbe.so.1 lrwxrwxrwx 1 root root 30 Jul 25 13:37 librte_pmd_null_crypto.so.1 -> ../librte_pmd_null_crypto.so.1 lrwxrwxrwx 1 root root 23 Jul 25 13:37 librte_pmd_null.so.1 -> ../librte_pmd_null.so.1 lrwxrwxrwx 1 root root 23 Jul 25 13:37 librte_pmd_ring.so.2 -> ../librte_pmd_ring.so.2 lrwxrwxrwx 1 root root 24 Jul 25 13:37 librte_pmd_vhost.so.1 -> ../librte_pmd_vhost.so.1 lrwxrwxrwx 1 root root 25 Jul 25 13:37 librte_pmd_virtio.so.1 -> ../librte_pmd_virtio.so.1 lrwxrwxrwx 1 root root 30 Jul 25 13:37 librte_pmd_vmxnet3_uio.so.1 -> ../librte_pmd_vmxnet3_uio.so.1
5.2 在编译前, 设置变量CONFIG_RTE_EAL_PMD_PATH
[root@D129 app]# cat ../.config |grep PATH CONFIG_RTE_EAL_PMD_PATH="/lib64/tong-dpdk-pmds/"
以上, dpdk app便可以使用 shared lib 正常运行了.
6. 另一个方案: 使用 -d, 需要神马加神马, 比如:
[root@D129 app]# ./testpmd -d ../lib/librte_pmd_virtio.so -d ../lib/librte_pmd_ixgbe.so
完.