DPDK的RTE_INIT初始化

DPDK代码中广泛使用RTE_INIT宏进行设备驱动或者RTE模块等的初始化工作,其核心是RTE_INIT_PRIO宏,定义在文件rte_common.h中。如下可见,RTE_INIT_PRIO宏的实现,实际为一个附带GCC编译属性的函数定义。此处用到两个属性,constructor和used。其中后一个used比较简单,向GCC编译器表明此函数的有用性,即使函数没有被任何地方引用,也不要警告。constructor构造属性,类似C++的构造函数,其标注的函数将在主函数(main)之前执行,相关代码位于目标文件的.ctors区(section)。

lib/librte_eal/common/include/rte_common.h

#define RTE_INIT_PRIO(func, prio) \
static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)

另外RTE_PRIO宏指定了constructor的优先级,即函数执行的顺序,值越小优先级越高。目前定义了4个优先级:RTE_PRIORITY_LOG、RTE_PRIORITY_BUS、RTE_PRIORITY_CLASS和RTE_PRIORITY_LAST。

#define RTE_PRIORITY_LOG 101
#define RTE_PRIORITY_BUS 110
#define RTE_PRIORITY_CLASS 120
#define RTE_PRIORITY_LAST 65535

#define RTE_PRIO(prio) RTE_PRIORITY_ ## prio

其中RTE_INIT宏封装了RTE_PRIORITY_LAST优先级的函数。RTE_REGISTER_BUS宏封装了RTE_PRIORITY_BUS优先级的函数。而RTE_REGISTER_CLASS宏封装了RTE_PRIORITY_CLASS优先级的函数。目前DPDK中RTE_PRIORITY_LOG优先级的函数仅有一个rte_log_init,优先级最高,最先初始化(函数所在文件:lib/librte_eal/common/eal_common_log.c)。

#define RTE_INIT(func) RTE_INIT_PRIO(func, LAST)

lib/librte_eal/common/include/rte_bus.h

#define RTE_REGISTER_BUS(nm, bus) \
RTE_INIT_PRIO(businitfn_ ##nm, BUS) \
{\
    (bus).name = RTE_STR(nm);\
    rte_bus_register(&bus); \
}

lib/librte_eal/common/include/rte_class.h

#define RTE_REGISTER_CLASS(nm, cls) \
RTE_INIT_PRIO(classinitfn_ ##nm, CLASS) \
{\
    (cls).name = RTE_STR(nm); \
    rte_class_register(&cls); \
}

如下编译DPDK的examples,如vhost程序,查看生成的map文件(vhost-switch.map),检查constructor属性生成的初始化构造函数:

$ cd examples/vhost
$ export RTE_SDK=/home/k/network/dpdk-19.02
$ export RTE_TARGET=build
$ make
  CC main.o
  CC virtio_net.o
  LD vhost-switch
  INSTALL-APP vhost-switch
  INSTALL-MAP vhost-switch.map
$
$ vi build/app/vhost-switch.map

如下所示,可见按照优先级顺序排列的初始化函数,优先级最低的RTE_PRIORITY_LAST未显示其数值。

 .init_array     0x000000000099e400      0x670
                 0x000000000099e400                PROVIDE (__init_array_start, .)
  *(SORT(.init_array.*) SORT(.ctors.*))
  .init_array.00101
                 0x000000000099e400        0x8 /home/k/network/dpdk-19.02/build/lib/librte_eal.a(eal_common_log.o)
  .init_array.00110
                 0x000000000099e408        0x8 /home/k/network/dpdk-19.02/build/lib/librte_bus_pci.a(pci_common.o)
  .init_array.00110
                 0x000000000099e410        0x8 /home/k/network/dpdk-19.02/build/lib/librte_bus_vdev.a(vdev.o)
  .init_array.00110
                 0x000000000099e418        0x8 /home/k/network/dpdk-19.02/build/lib/librte_bus_dpaa.a(dpaa_bus.o)
  .init_array.00110
                 0x000000000099e420        0x8 /home/k/network/dpdk-19.02/build/lib/librte_bus_fslmc.a(fslmc_bus.o)
  .init_array.00110
                 0x000000000099e428        0x8 /home/k/network/dpdk-19.02/build/lib/librte_bus_vmbus.a(vmbus_common.o)
  .init_array.00110
                 0x000000000099e430        0x8 /home/k/network/dpdk-19.02/build/lib/librte_bus_ifpga.a(ifpga_bus.o)
  .init_array.00120
                 0x000000000099e438        0x8 /home/k/network/dpdk-19.02/build/lib/librte_ethdev.a(rte_class_eth.o)
  *(.init_array EXCLUDE_FILE(*crtend?.o *crtend.o *crtbegin?.o *crtbegin.o) .ctors)
  .init_array    0x000000000099e440        0x8 /usr/lib/gcc/x86_64-linux-gnu/7/crtbeginS.o
  .init_array    0x000000000099e448        0x8 /home/k/network/dpdk-19.02/build/lib/librte_ip_frag.a(ip_frag_internal.o)
  .init_array    0x000000000099e450        0x8 /home/k/network/dpdk-19.02/build/lib/librte_lpm.a(rte_lpm.o)

通过查看DPDK代码可见,各个函数在vhost-switch.map中的顺序与其在代码中的注册的优先级相符。

lib/librte_eal/common/eal_common_log.c RTE_INIT_PRIO(rte_log_init, LOG)

drivers/bus/pci/pci_common.c      RTE_REGISTER_BUS(pci, rte_pci_bus.bus);
drivers/bus/vdev/vdev.c           RTE_REGISTER_BUS(vdev, rte_vdev_bus);
drivers/bus/dpaa/dpaa_bus.c       RTE_REGISTER_BUS(FSL_DPAA_BUS_NAME, rte_dpaa_bus.bus);
drivers/bus/fslmc/fslmc_bus.c     RTE_REGISTER_BUS(FSLMC_BUS_NAME, rte_fslmc_bus.bus);
drivers/bus/vmbus/vmbus_common.c  RTE_REGISTER_BUS(vmbus, rte_vmbus_bus.bus);
drivers/bus/ifpga/ifpga_bus.c     RTE_REGISTER_BUS(IFPGA_BUS_NAME, rte_ifpga_bus);

lib/librte_ethdev/rte_class_eth.c RTE_REGISTER_CLASS(eth, rte_class_eth);

另外,DPDK中定义了RTE_FINI相关宏,其使用了GCC的destructor和used两个属性,used的意义与RTE_INIT中的相同。destructor属性表明函数在主函数(main)结束之后执行。不过目前,在DPDK代码中并没有地方使用RTE_FINI宏。

lib/librte_eal/common/include/rte_common.h

#define RTE_FINI_PRIO(func, prio) \
static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)

#define RTE_FINI(func)  RTE_FINI_PRIO(func, LAST)


lib/librte_eal/common/include/rte_class.h

#define RTE_UNREGISTER_CLASS(nm, cls) \
RTE_FINI_PRIO(classfinifn_ ##nm, CLASS) \
{ \
    rte_class_unregister(&cls); \
}

DPDK版本dpdk-19.02。

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页