dpdk-2.helloword源码

参考资料

dpdk第二课------helloworld源码剖析
DPDK 环境适配层EAL

前言

dpdk的example-helloworld学习

源码

c 复制代码
/* 在逻辑核心上启动一个处理函数 */
static int
lcore_hello(__rte_unused void *arg)
{
    unsigned lcore_id;
    lcore_id = rte_lcore_id();   // 获取当前函数所使用的lcore逻辑核心
    printf("hello from core %u\n", lcore_id);
    return 0;
}
  
int main(int argc, char **argv)
{
    int ret;
    unsigned lcore_id;
    
    // EAL 初始化
    ret = rte_eal_init(argc, argv);
    if (ret < 0)
        rte_panic("Cannot init EAL\n");
        
    /* 设置日志级别 */
    rte_log_set_level(RTE_LOGTYPE_EAL, RTE_LOG_DEBUG);

    // master - worker 架构
    // 遍历每一个worker逻辑核心,并在worker核心上运行lcore_hello函数
    RTE_LCORE_FOREACH_WORKER(lcore_id) {
        rte_eal_remote_launch(lcore_hello, NULL, lcore_id);
    }   
    /* 在main核心上也调用lcore_hello 函数 */
    lcore_hello(NULL);
    // 等待线程结束。
    rte_eal_mp_wait_lcore();
    /* clean up the EAL */
    rte_eal_cleanup();

    return 0;
}

EAL

EAL 初始化通过调用 DPDK 的rte_eal_init()函数完成,该过程会处理一系列关键操作,主要包括:

  1. 命令行参数解析解析启动 DPDK 应用时传入的命令行参数(如核心掩码、大页配置、设备绑定等),常见参数包括:

    • -c <core_mask>:指定应用使用的 CPU 核心(通过掩码表示,如-c 0x3表示使用核心 0 和 1);
    • -n <num>:指定内存通道数(与 CPU 内存控制器相关);
    • --huge-dir <path>:指定大页内存的挂载路径;
    • -w <pci_addr>:指定需要绑定的 PCI 设备(如网卡)。
  2. 大页内存初始化 DPDK 为减少内存访问延迟、避免 TLB(Translation Lookaside Buffer) miss,依赖大页内存(Hugepages)。EAL 初始化会:

    • 检查系统是否配置了足够的大页内存(通常需要提前在系统中预留,如echo 1024 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages);
    • 挂载大页内存到指定目录(如/mnt/huge);
    • 为 DPDK 应用分配大页内存池,供后续数据包缓冲区(如rte_mbuf)使用。
  3. CPU 核心管理为避免操作系统进程调度带来的延迟,DPDK 通常将线程绑定到特定的 CPU 核心(核绑定)。EAL 初始化会:

    • 识别系统中的 CPU 核心拓扑(如物理核、逻辑核、NUMA 节点);
    • 根据-c参数预留指定的 CPU 核心,避免被其他进程占用;
    • 提供核心绑定接口(如rte_eal_remote_launch()),供后续应用线程绑定使用。
  4. PCI 设备探测与初始化DPDK 需要直接操作网卡等 PCIe 设备(绕过操作系统内核协议栈),EAL 初始化会:

    • 扫描系统中的 PCI 设备,识别支持 DPDK 的网卡(如 Intel、Mellanox 等厂商的高性能网卡);
    • 将指定的 PCI 设备(通过-w参数)从操作系统内核驱动(如ixgbe)解绑,重新绑定到 DPDK 兼容的用户态驱动(如vfio-pciuio_pci_generic);
    • 为设备分配资源(如 I/O 内存、中断),并初始化设备硬件队列(如收包队列、发包队列)。
  5. 其他基础组件初始化

    • 日志系统:初始化日志输出(控制台、文件)和级别控制;
    • 内存池(Mempool):创建默认的内存池,用于管理数据包缓冲区;
    • 多进程 / 多线程支持:初始化进程间通信(IPC)机制(如共享内存),支持多进程模式;
    • 计时器:初始化高精度计时器,供性能统计或定时任务使用。

核心

DPDK 应用通常运行在多个 CPU 核心上,这些核心被分为两类:

  • 主核心(master lcore) :负责初始化 EAL、管理全局资源(如设备配置、内存池)等 "控制平面" 工作,通常是 EAL 初始化时第一个被启用的核心(由-c参数指定的核心掩码中,序号最小的核心)。
  • 工作核心(worker lcore) :负责 "数据平面" 的核心工作(如数据包收发、解析、转发等),是除 master 之外的所有被 EAL 启用的核心。

RTE_LCORE_FOREACH_WORKER

RTE_LCORE_FOREACH_WORKER 宏的核心功能是迭代遍历所有 worker lcore,方便开发者在每个 worker 核心上部署并行任务(如启动数据包处理线程)。

c 复制代码
#define RTE_LCORE_FOREACH_WORKER(lc) \
    for (lc = rte_get_next_lcore(-1, 1, 0); lc < RTE_MAX_LCORE; \
        lc = rte_get_next_lcore(lc, 1, 0))
  • 参数 lc:循环变量,用于存储当前遍历到的 worker lcore 的 ID(逻辑核心编号)。
  • rte_get_next_lcore(-1, 1, 0):从第一个核心开始查找,1 表示只返回 worker lcore(排除 master),0 表示不循环查找

rte_eal_remote_launch

rte_eal_remote_launch 是一个核心函数,用于在指定的逻辑核心(lcore)上启动一个用户定义的函数,是实现多核心并行任务调度的关键接口。它的设计目标是将数据平面的处理逻辑(如数据包收发、转发)绑定到特定的 CPU 核心,避免操作系统调度带来的延迟,从而保证高性能。

c 复制代码
int rte_eal_remote_launch(int (*f)(void *), void *arg, unsigned int lcore_id);
  • 参数解析
    • f:函数指针,指向要在目标 lcore 上执行的任务函数(返回值为int,参数为void *)。
    • arg:传递给任务函数f的参数(可以是任意类型的指针,需自行保证生命周期)。
    • lcore_id:目标逻辑核心的 ID(必须是 EAL 初始化时通过-c参数启用的 lcore,否则会失败)。
  • 返回值
    • 成功:返回0(函数已被提交到目标 lcore 的任务队列,等待执行)。
    • 失败:返回-1(可能原因:lcore_id无效、目标 lcore 未启用、该 lcore 已有任务在运行等)。

通过管道发送唤醒信号,通知worker线程任务。

相关推荐
摇滚侠3 小时前
Spring Boot3零基础教程,SpringSecurity 测试,笔记81
spring boot·笔记·后端
华仔啊3 小时前
Go 语言未来会取代 Java 吗?别争了,先看完这篇再说
java·后端·go
IT_陈寒3 小时前
SpringBoot 3.2新特性实战:这5个隐藏功能让我开发效率提升50%
前端·人工智能·后端
申阳4 小时前
2小时个人公司:一个全栈开发的精益创业之路
前端·后端·程序员
草明4 小时前
当 Go 的 channel 被 close 后读写操作会怎么样?
开发语言·后端·golang
jakeswang4 小时前
Jenkins 已成过去式!新兴替代工具GitHub Actions即将崛起
后端·jenkins·github actions
合作小小程序员小小店4 小时前
大屏开发,在线歌词舆情分析系统demo,基于python,flask,web,echart,nlp,自然语言数据库mysql。
后端·python·flask·nlp·echarts
武子康5 小时前
大数据-138 ClickHouse MergeTree 实战详解|分区裁剪 × 稀疏主键索引 × marks 标记 × 压缩
大数据·后端·nosql