You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux内核__netif_receive_skb_core中pt_prev作用及ptype遍历逻辑疑问

Linux内核__netif_receive_skb_core中ptype遍历逻辑的设计意图

在分析Linux内核收包处理函数__netif_receive_skb_core时,会发现它对ptype(协议类型处理结构体)的遍历逻辑比较特殊:

pt_prev = NULL;

list_for_each_entry_rcu(ptype, &ptype_all, list) {
        if (pt_prev)
                ret = deliver_skb(skb, pt_prev, orig_dev);
        pt_prev = ptype;
}

list_for_each_entry_rcu(ptype, &skb->dev->ptype_all, list) {
        if (pt_prev)
                ret = deliver_skb(skb, pt_prev, orig_dev);
        pt_prev = ptype;
}

// 注:完整代码中此处还有处理最后一个pt_prev的逻辑
// if (pt_prev)
//         ret = deliver_skb(skb, pt_prev, orig_dev);

很多人会疑惑,为什么不直接用更直观的遍历逻辑:

list_for_each_entry_rcu(ptype, &ptype_all, list)
    ret = deliver_skb(skb, ptype, orig_dev);

这种“先交付前一个ptype、再保存当前ptype到pt_prev”的设计,核心目的是适配RCU机制下的链表安全遍历,同时避免处理逻辑干扰遍历流程,具体原因有两点:

  • 规避RCU遍历中的节点删除风险:deliver_skb的调用可能触发协议模块卸载,导致对应的ptype节点从RCU链表中被移除。RCU读临界区允许删除节点,但如果遍历当前节点时就调用deliver_skb,万一该节点被删除,后续的链表迭代可能出现指针失效问题。延迟一个节点处理,先完成当前节点的遍历再处理上一个,能确保遍历过程不受节点删除的干扰——RCU保证已遍历的节点在读临界区结束前不会被释放,处理pt_prev是安全的。

  • 防止skb提前释放中断遍历:deliver_skb内部可能调用kfree_skb释放当前skb,如果遍历过程中直接处理当前节点,skb被释放后,后续遍历访问skb->dev->ptype_all等字段会触发空指针错误。延迟处理能确保先完成整个链表的节点遍历,再逐个处理ptype,即使某个ptype释放了skb,也不会影响已经完成的遍历步骤。

内容的提问来源于stack exchange,提问作者yuanjianpeng

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 23:47:45