DPDK程式初始化遇到"tailq is already registered"錯誤
程式連結了DPDK庫,啟動就出錯,打出如下資訊:
EAL: UIO_RESOURCE_LIST tailq is already registered PANIC in tailqinitfn_rte_uio_tailq(): Cannot initialize tailq: UIO_RESOURCE_LIST
分析發現,C語言定義constructor屬性的函式會先於main()執行,DPDK中定義了RTE_INIT()巨集,用來宣告一個如建構函式:
#define RTE_PRIO(prio) \ RTE_PRIORITY_ ## prio /** * Run function before main() with high priority. * * @param func * Constructor function. * @param prio * Priority number must be above 100. * Lowest number is the first to run.*/ #ifndef RTE_INIT_PRIO /* Allow to override from EAL */ #define RTE_INIT_PRIO(func, prio) \ static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void) #endif /** * Run function before main() with low priority. * * The constructor will be run after prioritized constructors. * * @param func * Constructor function.*/ #define RTE_INIT(func) \ RTE_INIT_PRIO(func, LAST)
在tailq.h中定義了EAL_REGISTER_TAILQ()
/** * Register a tail queue. * * Register a tail queue from shared memory. * This function is mainly used by EAL_REGISTER_TAILQ macro which is used to * register tailq from the different dpdk libraries. Since this macro is a * constructor, the function has no access to dpdk shared memory, so the * registered tailq can not be used before call to rte_eal_init() which calls * rte_eal_tailqs_init(). * * @param t * The tailq element which contains the name of the tailq you want to * create (/retrieve when in secondary process). * @return * 0 on success or -1 in case of an error.*/ int rte_eal_tailq_register(struct rte_tailq_elem *t); #define EAL_REGISTER_TAILQ(t) \ RTE_INIT(tailqinitfn_ ##t) \ { \ if (rte_eal_tailq_register(&t) < 0) \ rte_panic("Cannot initialize tailq: %s\n", t.name); \ }
然後用定義了很多初始化建構函式,比如rte_ring.c中:
#define RTE_TAILQ_RING_NAME "RTE_RING" static struct rte_tailq_elem rte_ring_tailq = { .name = RTE_TAILQ_RING_NAME, }; EAL_REGISTER_TAILQ(rte_ring_tailq)
所以原因是涉及到的constructor函式程式碼有多個例項,被重複呼叫。我遇到的例項是因為有重複靜態連結:app連結了libxxx.a和librte_*.a,並且libxxx.a也連結了librte_*.a,app裡面就有兩份librte_*.a的程式碼例項。
解決方法:把靜態連結librte_*.a都改成動態連結librte_*.so
加入log,可發現在main()函式之前呼叫了很多EAL_REGISTER_TAILQ()函式:
EAL: rte_eal_tailq_register: name=RTE_RING
EAL: rte_eal_tailq_register: name=RTE_MEMPOOL
EAL: rte_eal_tailq_register: name=RTE_MBUF_DYNFIELD
EAL: rte_eal_tailq_register: name=RTE_MBUF_DYNFLAG
EAL: rte_eal_tailq_register: name=RTE_HASH
EAL: rte_eal_tailq_register: name=RTE_FBK_HASH
EAL: rte_eal_tailq_register: name=RTE_THASH
EAL: rte_eal_tailq_register: name=RTE_ACL
EAL: rte_eal_tailq_register: name=RTE_DIST_BURST
EAL: rte_eal_tailq_register: name=RTE_DISTRIBUTOR
EAL: rte_eal_tailq_register: name=RTE_EFD
EAL: rte_eal_tailq_register: name=RTE_KNI
EAL: rte_eal_tailq_register: name=RTE_LPM
EAL: rte_eal_tailq_register: name=RTE_LPM6
EAL: rte_eal_tailq_register: name=RTE_MEMBER
EAL: rte_eal_tailq_register: name=RTE_RIB
EAL: rte_eal_tailq_register: name=RTE_RIB6
EAL: rte_eal_tailq_register: name=RTE_REORDER
EAL: rte_eal_tailq_register: name=RTE_STACK
EAL: rte_eal_tailq_register: name=RTE_IPSEC_SAD
EAL: rte_eal_tailq_register: name=RTE_FIB
EAL: rte_eal_tailq_register: name=RTE_FIB6