非root用户使用dpdk初始化失败
错误内容
非root用户使用dpdk初始化失败时(root用户没有问题),报错:Cannot obtain physical addresses: No such file or directory
尝试解决方案
查看了dpdk官方文档,非root用户需要修改某些文件的权限,但是该修改的权限也修改了,还是一样的问题。比如:
chmod o+rw /dev/hugepages
chmod o+rw /dev/uio*
chmod o+rw /sys/class/uio/uio*/device/config
chmod o+rw /sys/class/uio/uio*/device/resource*
然后看了源代码,主要是在检测是否能访问物理地址时报的错误。可以分析到,主要是没有权限访问物理地址。
最终解决方案(二选其一):
- IOVA模式改VA。默认为PA模式,所以在初始化是增加参数:--iova-mode va 就可以了。
- 为你的应用增加特权:setcap CAP_SYS_ADMIN+ep 你的应用
参考的源代码:
...
int
rte_eal_using_phys_addrs(void)
{
if (phys_addrs_available == -1) {
uint64_t tmp = 0;
if (rte_eal_has_hugepages() != 0 &&
rte_mem_virt2phy(&tmp) != RTE_BAD_PHYS_ADDR)
phys_addrs_available = 1;
else
phys_addrs_available = 0;
}
return phys_addrs_available;
}
...
phys_addr_t
rte_mem_virt2phy(const void *virtaddr)
{
int fd, retval;
uint64_t page, physaddr;
unsigned long virt_pfn;
int page_size;
off_t offset;
if (phys_addrs_available == 0)
return RTE_BAD_IOVA;
/* standard page size */
page_size = getpagesize();
fd = open("/proc/self/pagemap", O_RDONLY);
if (fd < 0) {
RTE_LOG(INFO, EAL, "%s(): cannot open /proc/self/pagemap: %s\n",
__func__, strerror(errno));
return RTE_BAD_IOVA;
}
virt_pfn = (unsigned long)virtaddr / page_size;
offset = sizeof(uint64_t) * virt_pfn;
if (lseek(fd, offset, SEEK_SET) == (off_t) -1) {
RTE_LOG(INFO, EAL, "%s(): seek error in /proc/self/pagemap: %s\n",
__func__, strerror(errno));
close(fd);
return RTE_BAD_IOVA;
}
retval = read(fd, &page, PFN_MASK_SIZE);
close(fd);
if (retval < 0) {
RTE_LOG(INFO, EAL, "%s(): cannot read /proc/self/pagemap: %s\n",
__func__, strerror(errno));
return RTE_BAD_IOVA;
} else if (retval != PFN_MASK_SIZE) {
RTE_LOG(INFO, EAL, "%s(): read %d bytes from /proc/self/pagemap "
"but expected %d:\n",
__func__, retval, PFN_MASK_SIZE);
return RTE_BAD_IOVA;
}
/*
* the pfn (page frame number) are bits 0-54 (see
* pagemap.txt in linux Documentation)
*/
if ((page & 0x7fffffffffffffULL) == 0)
return RTE_BAD_IOVA;
physaddr = ((page & 0x7fffffffffffffULL) * page_size)
+ ((unsigned long)virtaddr % page_size);
return physaddr;
}
...