DPU网络开发SDK—DPDK(三)

13 篇文章 3 订阅

rte_eal_init()

接上次内容继续对rte_eal_init所做的工作进行分析。

6. 将DPDK进程的启动参数保留下来

在启动DPDK进程时会传入启动参数,这些参数会分成两部分,一部分是DPDK的eal配置参数,如占用的CPU处理核的列表,分配的大页内存大小,网卡的黑白名单等;另外一部分是进程自定义参数,由开发者自行定义参数列表和含义。参数列表中eal配置参数放在前面,进程自定义参数在后面,中间通过“--”进行分割。

eal_save_args()中,分配两段内存空间并交给两个全局的变量eal_args和eal_app_args,后将两部分参数分别存放在这两段内存空间当中。

7. CPU处理核信息初始化

存在一个全局数组变量lcore_config,类型为struct lcore_config,大小由宏定义RTE_MAX_LCORE指定。在rte_eal_cpu_init()中,首先依次遍历数组中的每个元素并对struct lcore_config中的一些元素赋默认值。该结构体的数据结构包含如下内容: 

struct lcore_config {
   pthread_t thread_id;       // lcore绑定线程的标识符
   int pipe_main2worker[2];   // 从main到worker管道标识
   int pipe_worker2main[2];   // 从worker到main的管道标识


   lcore_function_t * volatile f; // lcore绑定线程的入口函数
   void * volatile arg;       // 入口函数的传入参数
   volatile int ret;          // 线程入口函数的返回值


   volatile enum rte_lcore_state_t state; // lcore的状态
   unsigned int socket_id;    // 该lcore所属CPU的socket id
   unsigned int core_id;      // 该lcore在CPU上的物理核
   int core_index;            // 该lcore的相对索引,从0开始
   uint8_t core_role;         // 该lcore的角色,可选项有OFF, RTE, SERVICE


   rte_cpuset_t cpuset;       // 该lcore对应的主机CPU的lcore的mask
};

要理解该结构体中一些元素的含义,首先需要了解一下CPU的结构。在Linux中执行lscpu命令,可得到如下输出内容:

root@Soc:~# lscpu
Architecture:        x86_64
CPU op-mode(s):      32-bit, 64-bit
Byte Order:          Little Endian
Address sizes:       46 bits physical, 57 bits virtual
CPU(s):             16
On-line CPU(s) list:    0-15
Thread(s) per core:  2
Core(s) per socket:  8
Socket(s):          1

该例子的主机中,有一个socket。socket可以对应主板上的一个CPU插槽,也就是一块CPU芯片。对于一般的PC机来说,只有一个socket,大型服务器一般有多个socket。一个socket中一般会有多个core,即一个独立的处理单元,在单线程模式下,一个独立的处理单元包含一套标准的寄存器和L1级缓存,同时刻只能运行一个线程;而多线程模式下,一套处理单元有两套寄存器,同时刻可以运行两个线程,这两个线程共享L1级缓存。上例中所显示的主机的CPU有8个处理单元,因为开启了多线程,每个处理单元线程数是2,这样逻辑上讲一共有16个线程(或CPU)。

对应到lcore_config中的相关结构,socket_id即为socket的编号,core_id对应的是处理单元的编号,而DPDK的处理核lcore则对应的是线程(或CPU)的编号。

在遍历lcore_config的每个元素时的索引就是lcore的编号,遍历时,根据lcore的编号去系统中查找对应的线程(或CPU)。如果该线程没有被启用,则将lcore_config结构体中的core_index置位负数,并将rte_config中的lcore_role中对应的值置为ROLE_OFF;线程被启用时,core_index设置为相对索引,lcore_role设为ROLE_RTE。

遍历完lcore之后,也就能够统计出涉及到的socket有哪些了,会根据这些信息设置rte_config中的numa_node信息。

需要另外指出的是,rte_eal_cpu_init()中涉及到的某些func,是通过直接访问sys文件系统实现的。如eal_cpu_socket_id()是遍历/sys/devices/system/node/nodeX目录中如果存在cpuY目录,则lcoreY的socket id是X;eal_cpu_detected()是遍历/sys/devices/system/cpu/cpuX/topology/core_id是否存在。

8. DPDK参数解析

eal_parse_args()是解析DPDK参数,比较重要的几个参数有:

  • -a:allow list,指定哪些网卡设备是允许被DPDK接管的,传入的参数值是设备的pci总线编号。

  • -b:block list,指定哪些网卡设备是进制被DPDK禁止的,传入值同上。

  • -c:指定DPDK进程所占用的处理核是哪些,用bitmask的方式进行表示。

  • -m:指定分配多大的内存空间给DPDK的内存池,以MB为单位。

解析之后的信息存放在internal_config这个全局变量或者其他的变量当中。DPDK涉及到的参数比较多,后续会根据需要补充说明各参数的含义。

9. 插件初始化

如果是Windows系统,是不支持插件动态载入的,eal_plugins_init()的内容为空。是Linux系统时,如果能通过执行系统调用dlopen打开动态链接库librte_eal.so.XX,则调用eal_plugin_add将默认动态库的目录default_solib_dir添加到全局变量solib_list当中(此外还可以通过DPDK的启动参数-d,将自定义目录添加到solib_list中)。

由于在初始化阶段加入solib_list中的可能是动态库本身也可能是动态库所在的目录,eal_plugins_init()会在遍历solib_list中将目录中的*.so文件全部遍历之后加入solib_list中;如果已经是*.so本身,则设置solib的lib_handle。

10. 初始化跟踪功能

调用eal_trace_init()初始化跟踪功能,该功能是对一些事件和变量进行跟踪,用于多线程同步和时间度量等。该功能比较复杂,后续分析过程中会详细介绍,此处先略过。

11. 解析设备

前面提到DPDK的参数时,-a和-b参数分别指定网卡设备的白黑名单,这些信息是存放在devopt_list这个全局变量当中的,eal_option_device_parse()会遍历其中的每个设备,并转换成新的数据结构存放在devargs_list当中。

未完待续…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值