netif_receive_skb 函数解析

本文深入探讨了Linux内核中网络数据包的接收处理流程,包括数据包类型匹配、网桥与MAC VLAN模块的特殊处理以及不同类型数据包的特定处理函数,如ip_rcv()与arp_rcv()。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

int netif_receive_skb(struct sk_buff *skb)
{
   //略去一些代码
    rcu_read_lock();
    //第一步:先处理 ptype_all 上所有的 packet_type->func()           
    //所有包都会调func,对性能影响严重!内核默认没挂任何钩子函数

    list_for_each_entry_rcu(ptype, &ptype_all, list) { //遍历ptye_all链表
        if (!ptype->dev || ptype->dev == skb->dev) {    //上面的paket_type.type 为 ETH_P_ALL
            if (pt_prev)                                //对所有包调用paket_type.func()
                ret = deliver_skb(skb, pt_prev, orig_dev); //此函数最终调用paket_type.func()
            pt_prev = ptype;
        }
    }
    //第二步:若编译内核时选上BRIDGE,下面会执行网桥模块
    //调用函数指针 br_handle_frame_hook(skb), 在动态模块 linux_2_6_24/net/bridge/br.c中
    //br_handle_frame_hook = br_handle_frame;
    //所以实际函数 br_handle_frame。
    //注意:在此网桥模块里初始化 skb->pkt_type 为 PACKET_HOST、PACKET_OTHERHOST

    skb = handle_bridge(skb, &pt_prev, &ret, orig_dev);
    if (!skb) goto out;

    //第三步:编译内核时选上MAC_VLAN模块,下面才会执行
    //调用 macvlan_handle_frame_hook(skb), 在动态模块linux_2_6_24/drivers/net/macvlan.c中
    //macvlan_handle_frame_hook = macvlan_handle_frame; 
    //所以实际函数为 macvlan_handle_frame。 
    //注意:此函数里会初始化 skb->pkt_type 为 PACKET_BROADCAST、PACKET_MULTICAST、PACKET_HOST

    skb = handle_macvlan(skb, &pt_prev, &ret, orig_dev);
    if (!skb)  goto out;

    //第四步:最后 type = skb->protocol; &ptype_base[ntohs(type)&15]
    //处理ptype_base[
ntohs(type)&15]上的所有的 packet_type->func()
    //根据第二层不同协议来进入不同的钩子函数,重要的有:ip_rcv() arp_rcv()
    type = skb->protocol;
    list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type)&15], list) {
        if (ptype->type == type &&                      //遍历包type所对应的链表
            (!ptype->dev || ptype->dev == skb->dev)) {  //调用链表上所有pakcet_type.func()
            if (pt_prev)
                ret = deliver_skb(skb, pt_prev, orig_dev); //就这里!arp包会调arp_rcv()
            pt_prev = ptype;                               //        ip包会调ip_rcv()
        }
    }
    if (pt_prev) {
        ret = pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
    } else {               //下面就是数据包从协议栈返回来了
        kfree_skb(skb);    //注意这句,若skb没进入socket的接收队列,则在这里被释放
        ret = NET_RX_DROP; //若skb进入接收队列,则系统调用取包时skb释放,这里skb引用数减一而已
    }
out:
    rcu_read_unlock();
    return ret;
}

int deliver_skb(struct sk_buff *skb,struct packet_type *pt_prev, struct net_device *orig_dev){
    atomic_inc(&skb->users);
    return pt_prev->func(skb, skb->dev, pt_prev, orig_dev);//调函数ip_rcv() arp_rcv()等
}
<think>我们正在处理关于Linux内核网络子系统中`netif_receive_skb_internal`函数的使用和故障排除的问题。根据提供的引用,我们可以总结以下信息: 引用[2]提到:`netif_receive_skb_internal`函数是`netif_receive_skb`函数内部调用的实际处理数据包的函数。它处理网络数据包(由`struct sk_buff`表示)并负责将其传递给上层协议栈。 引用[3]提到:软中断处理程序`net_rx_action`会调用驱动程序的`poll()`函数,而`poll()`函数会调用`netif_receive_skb()`,然后逐一把接收到的数据包发送到上层。 引用[4]提到:`netif_rx`函数通过软中断将数据包提交给网络协议栈,以减少硬件中断处理时间。 因此,我们可以推断`netif_receive_skb_internal`是在软中断上下文中被调用的,用于将数据包传递到网络协议栈的上层。 关于使用和故障排除,我们可以从以下几个方面考虑: 1. **功能**:`netif_receive_skb_internal`负责处理接收到的数据包,包括检查数据包是否需要重定向(例如,用于数据包捕获或网络分流),以及将数据包传递给上层协议处理函数(如IP层)。 2. **常见问题**: - 数据包丢失:如果在该函数中处理数据包时出现问题,可能会导致数据包被丢弃。 - 性能问题:由于该函数在软中断上下文中运行,如果处理时间过长,可能会导致网络延迟增加或软中断负载过高。 3. **调试方法**: - 使用内核跟踪(tracepoint):`trace_netif_receive_skb`和`trace_netif_receive_skb_exit`可用于跟踪数据包在该函数中的处理情况。 - 使用`dropwatch`工具监视内核中数据包丢弃的情况。 - 使用`perf`工具分析软中断的CPU使用情况。 4. **使用场景**:该函数是内核网络栈接收路径的核心部分,任何通过网络接口进入系统的数据包都会经过此函数(除非使用了其他接收路径,如NAPI)。 下面我们根据以上信息组织回答。</think>### Linux内核netif_receive_skb_internal函数详解 #### 功能概述 `netif_receive_skb_internal()`是Linux内核网络子系统中的核心函数,主要负责将接收到的网络数据包(`struct sk_buff`)传递给上层协议栈。该函数在软中断(softirq)上下文中执行,其主要功能包括: 1. **数据包分发**:根据数据包类型(以太网类型)调用相应的协议处理函数(如IP、ARP等) 2. **分流处理**:支持RPS(Receive Packet Steering)实现多核负载均衡 3. **数据包捕获**:为`tcpdump`等工具提供抓包接口(`ptype_all`链表) 4. **拥塞控制**:实现GRO(Generic Receive Offload)数据包合并优化 5. **协议处理**:最终通过`__netif_receive_skb_core()`完成协议栈分发[^2] #### 典型调用路径 ```mermaid graph TD A[网卡硬件中断] --> B[NAPI poll] B --> C[netif_receive_skb] C --> D[netif_receive_skb_internal] D --> E[__netif_receive_skb_core] E --> F[IP/ARP协议处理] ``` #### 常见故障排查 1. **数据包丢失**: - 检查`/proc/net/softnet_stat`确认"dropped"计数 - 使用`dropwatch`工具监控丢包位置 ```bash $ dropwatch -l kas ``` 2. **CPU瓶颈**: - 通过`top`观察`si`(软中断)利用率 - 使用`perf`定位热点函数: ```bash $ perf record -e softirq:net_rx_action -ag ``` 3. **协议栈异常**: - 启用动态调试:`echo 'file net/core/dev.c +p' > /sys/kernel/debug/dynamic_debug/control` - 使用`ftrace`跟踪函数调用: ```bash $ echo netif_receive_skb_internal > set_ftrace_filter $ echo function > current_tracer ``` #### 性能优化建议 1. **调整GRO/GSO参数**: ```bash $ ethtool -K eth0 gro on $ sysctl -w net.core.netdev_max_backlog=30000 ``` 2. **启用RPS**(多核系统): ```bash # 将CPU掩码写入对应设备的rps_cpus $ echo f > /sys/class/net/eth0/queues/rx-0/rps_cpus ``` 3. **调整NAPI权重**: ```bash $ sysctl -w net.core.dev_weight=600 ``` #### 使用场景 该函数主要应用于: 1. 网络设备驱动接收路径 2. 虚拟网络设备(veth, bridge)的数据转发 3. 内核网络协议栈开发 4. XDP(eXpress Data Path)后处理阶段[^3] > **关键设计原理**:通过软中断延迟处理机制(softirq),在保证吞吐量的同时减少硬件中断时间,这对高速网络设备尤为重要[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值