本文以vpp双开为例来介绍下当时定位该问题的一个历程。
vpp版本18.07(其dpdk版本为18.05)
实验发现vpp(或dpdk)较新的版本天然支持多开,例如dpdk的19.08版本就天然支持,这里主要讲解下老版本不能双开(或新版本可以双开)的本质问题。
先来看下双开时报的错:Is another primary process running
找到这里就会发现是在rte_config_init初始化时出现问题了,由此根据rte在初始化流程中所作的处理基本可以猜测到可能是资源相关的地方出问题了(事实上的确是该地方出现问题了)。
其实找到上面的那句log信息位置(dpdk),再往上看就可以看出问题所在了,下面给出相应的截图:
dpdk_18.05的代码截图
dpdk_19.08的代码截图
问题都是一样的,双开时相当于两次fcntl操作了同一个文件(mem_cfg_fd),查看errno发现也是这样的retval的返回值是 11 即 EAGAIN /* Try again */
查看fcntl的man手册,man fcntl的ERROR的error码截图
多余的话不用解释,看到这里我想大家至少应该已经明白fcntl接口的错误用法会出现什么问题及报错了。
下面说下为什么18.05版本为什么会直接报错死掉,而19.08版本不出直接死掉。
其实很简单两个版本的log就不一样,一个是ret_exit,一个是RET_LOG,从log的level上就可以知道,18.05版本再出现该错误时要求极为严格,而19.08版本则处理的比较简单甚至直接忽略掉该问题。
下面直接说本质:18.05版本默认开启使用内存共享机制,而19.08版本相反不设置的话默认不适用内存共享机制,所以19.08版本认位该问题严重度较轻。但如果19.08版本在配置也开启内存共享机制的话(或者说在开发时需要使用内存共享机制的话),我想大家还得直面该问题,要不还会出现意想不到的事情。
下面说下如何修改该问题:其实很简单请看下面的截图,该截图来自 http://blog.sina.com.cn/s/blog_90cfda2f0102x58j.html 的blog。
很显然差异在 –file-prefix 选项上,该选项配置的name如果相同的话,就会出现双开的两个vpp(或dpdk)程序,在 fcntl 共享内存将要mmap的文件是同一个文件,上面已经说了不能对同一个文件多次进行fcntl操作,即使可以多次fcntl操作,也会导致两个程序在操作内存地址时发生意想不到的意外,所以18.05版本在这里做了操作失败直接退出的处理。
vpp_18.07双开后,看下fcntl操作的那个文件到底是谁:
就是这个**.vpp_config** 文件,双开时对代码处理后,两个文件分别是 .vpp1_config 和 .vpp11_config
也可以通过查看程序的fd来验证下。双开两个vpp程序时,gdb可以看到对应这个文件的fd返回值(我这里实验时都是fd=15),一开始还有点怀疑两个程序中的fd相同会不会有问题呀,年纪大了有时候脑子会突然断电,有些知识容易一时糊涂,所以就翻了翻《APUE》查了下文件描述符fd相关的内容,直接说结论-----(每一个文件描述符会与一个打开文件相对应,同时,不同的文件描述符也会指向同一个文件。相同的文件可以被不同的进程打开也可以在同一个进程中被多次打开。系统为每一个进程维护了一个文件描述符表,该表的值都是从0开始的,所以在不同的进程中你会看到相同的文件描述符,这种情况下相同文件描述符有可能指向同一个文件,也有可能指向不同的文件。),所以说虽然都是fd=15但没有毛关系。
ps -aux | grep vpp 查到连个vpp的pid,通过pid来看下这俩文件:
看看是吧,虽然fd都=15,但两文件不是同一个。
下面说下如何修改代码可以保证同时多开vpp:
主要在于配置问题,保证连两个vpp的地址空间相互独立。例如以下位置
类似于这些资源相关的地方建议都确保 互相不影响。
举个例子代码中这些地方都需要修改一下:
/src/plugins/dpdk/device/init.c — dpdk_config()
/src/svm/svm.c – svm_map_region()