侧边栏壁纸
  • 累计撰写 53 篇文章
  • 累计收到 3 条评论

P1-01 · EAL:用户态的"迷你内核启动器"

PacketForge
2026-08-18 / 0 评论 / 2 阅读 /
对应路线图:Phase 1 (Day 22-49) | DPDK 24.11.6 LTS | 内核对照 v6.6
代码出处:source/dpdk-stable-24.11.6/lib/eal/,引用均标 文件:行号
上一篇:无(系列第 1 篇)| 下一篇:P1-02 mempool

一句话定位

EAL(Environment Abstraction Layer)在用户态复刻了内核启动时做的那些事:CPU/拓扑检测、内存管理、设备枚举、中断处理、线程管理。rte_eal_init()(lib/eal/linux/eal.c:918)就是 DPDK 的 start_kernel。

启动主线:对着真实代码走一遍

EAL 启动十步与内核对应物

步骤真实调用行号内核对应
① 日志eal_log_init()eal.c:937printk 日志子系统
② CPU/lcore 检测rte_eal_cpu_init()eal.c:965setup_arch 拓扑发现
③ 参数解析eal_parse_args()eal.c:971内核 cmdline 解析
④ 运行时配置rte_config_init()eal.c:998编译期 .config
⑤ 中断线程rte_eal_intr_init()eal.c:1003irq 子系统
⑥ 总线扫描rte_bus_scan()eal.c:1025pci_scan_bus(drivers/pci/probe.c)
⑦ IOVA 模式选择自动探测逻辑eal.c:1032-1086IOMMU 使能检测
⑧ 大页+内存rte_eal_memory_init()eal.c:1087/1136memblock → buddy
⑨ worker 线程eal_worker_thread_create()eal.c:1197-1224kthread + 调度器
⑩ 设备探测rte_bus_probe()eal.c:1242driver probe(drivers/base/dd.c)

第 ⑦ 步:IOVA 自动选择(eal.c:1037-1064)

/* if no EAL option "--iova-mode=<pa|va>", use bus IOVA scheme */
if (internal_conf->iova_mode == RTE_IOVA_DC) {
    /* autodetect the IOVA mapping mode */
    enum rte_iova_mode iova_mode = bus_iova_mode;

    if (iova_mode == RTE_IOVA_DC) {
        EAL_LOG(DEBUG, "Buses did not request a specific IOVA mode.");

        if (!RTE_IOVA_IN_MBUF) {
            iova_mode = RTE_IOVA_VA;
            EAL_LOG(DEBUG, "IOVA as VA mode is forced by build option.");
        } else if (!phys_addrs) {
            /* if we have no access to physical addresses,
             * pick IOVA as VA mode.
             */
            iova_mode = RTE_IOVA_VA;
            EAL_LOG(DEBUG, "Physical addresses are unavailable, selecting IOVA as VA mode.");
        } else if (is_iommu_enabled()) {
            /* we have an IOMMU, pick IOVA as VA mode */
            iova_mode = RTE_IOVA_VA;
            EAL_LOG(DEBUG, "IOMMU is available, selecting IOVA as VA mode.");
        } else {
            /* physical addresses available, and no IOMMU
             * found, so pick IOVA as PA.
             */
            iova_mode = RTE_IOVA_PA;
            EAL_LOG(DEBUG, "IOMMU is not available, selecting IOVA as PA mode.");
        }
    }
    rte_eal_get_configuration()->iova_mode = iova_mode;
}

读出三层信息:① 有 IOMMU 就用 VA(网卡 DMA 走虚拟地址,P5 讲 DPU 时回来复习);② 优先级是"构建选项 > 物理地址可用性 > IOMMU 检测";③ 这就是 VFIO 绑定后 DPDK 默认跑 VA 模式的原因——rte_vfio_enable("vfio") 在 eal.c:1117。

第 ⑨ 步:worker lcore 怎么诞生(eal.c:1197-1224,节选)

RTE_LCORE_FOREACH_WORKER(i) {
    /*
     * create communication pipes between main thread
     * and children
     */
    if (pipe(lcore_config[i].pipe_main2worker) < 0)
        rte_panic("Cannot create pipe\n");
    if (pipe(lcore_config[i].pipe_worker2main) < 0)
        rte_panic("Cannot create pipe\n");

    lcore_config[i].state = WAIT;

    /* create a thread for each lcore */
    ret = eal_worker_thread_create(i);
    if (ret != 0)
        rte_panic("Cannot create thread\n");
    // ... 设置线程名 "dpdk-worker%d" ...
    ret = rte_thread_set_affinity_by_id(lcore_config[i].thread_id,
        &lcore_config[i].cpuset);
    if (ret != 0)
        rte_panic("Cannot set affinity\n");
}

两个细节:每个 worker lcore 有一对 pipe 与主线程通信(rte_eal_remote_launch 的底层机制);线程创建后立即绑核——lcore 模型的第一条纪律。之后主线程用 rte_eal_mp_remote_launch(sync_func, ...) 同步确认所有 worker 就绪(eal.c:1230-1231)。

三个关键概念

  • lcore:逻辑核。rte_lcore_id() 返回 EAL 编号;--lcores 可把 lcore 映射到任意物理核。
  • IOVA 模式:见上文判定链——RTE_IOVA_VA(需 IOMMU)vs RTE_IOVA_PA(无 IOMMU 兜底)。
  • 大页:DPDK 内存全部来自 hugepage(2M/1G),页表项少 → TLB miss 少。eal_hugepage_info_init() 读 /sys/kernel/mm/hugepages/(eal.c:1087-1098)。

🐧 内核对照

DPDK内核关键差异
rte_eal_init 一步步初始化start_kernel → rest_init内核在特权态,DPDK 全靠 sysfs/procfs 读信息
memseg 表 + 大页buddy allocator + zoneDPDK 内存一次性申请,之后零分配
轮询收包中断 + 软中断见 [P1-05 PMD 对照](/index.php/archives/29/)
lcore 绑核sched domain / CPU affinity内核调度器会迁移任务,DPDK 主动绑死

面试 3 问

  1. EAL 启动做了哪些事? → 背十步表,并说出每步的内核对应物。
  2. IOVA VA/PA 何时切换? → 复述 eal.c:1037-1064 判定链:构建选项 → 物理地址可用性 → IOMMU 检测。
  3. worker lcore 是怎么被拉起的? → 启动时创建线程 + 双向 pipe + 绑核 + 置 WAIT 态;运行时 rte_eal_remote_launch 经 pipe 下发函数。

🔧 动手实验

改造 examples/helloworld:每个 lcore 打印 rte_lcore_id()、物理 CPU、NUMA node。产出 code/P1/helloworld-plus/。


下一篇:P1-02 · mempool:预分配 + 每核缓存,消灭逐包分配

0

评论 (0)

取消