一、中文注释
/**
* netif_receive_skb - 从网络处理接收缓冲区
* @skb: 要处理的缓冲区
*
* netif_receive_skb() 是主要的数据接收处理函数。
* 它总是成功的。由于拥塞控制或协议层的原因,缓冲区可能在处理过程中被丢弃。
*
* 这个函数只能在软中断(softirq)上下文中调用,并且应该启用中断。
*
* 返回值(通常被忽略):
* NET_RX_SUCCESS: 无拥塞
* NET_RX_DROP: 数据包被丢弃
*/
int netif_receive_skb(struct sk_buff *skb)
{
trace_netif_receive_skb_entry(skb);
return netif_receive_skb_internal(skb);
}
EXPORT_SYMBOL(netif_receive_skb);
static int netif_receive_skb_internal(struct sk_buff *skb)
{
int ret;
net_timestamp_check(netdev_tstamp_prequeue, skb);
if (skb_defer_rx_timestamp(skb))
return NET_RX_SUCCESS;
if (static_branch_unlikely(&generic_xdp_needed_key)) {
int ret;
preempt_disable();
rcu_read_lock();
ret = do_xdp_generic(rcu_dereference(skb->dev->xdp_prog), skb);
rcu_read_unlock();
preempt_enable();
if (ret != XDP_PASS)
return NET_RX_DROP;
}
rcu_read_lock();
#ifdef CONFIG_RPS
// RPS (接收包处理软中断) 配置,用于多核系统的性能优化
if (static_key_false(&rps_needed)) {
struct rps_dev_flow voidflow, *rflow = &voidflow;
int cpu = get_rps_cpu(skb->dev, skb, &rflow);
if (cpu >= 0) {
ret = enqueue_to_backlog(skb, cpu, &rflow->last_qtail);
rcu_read_unlock();
return ret;
}
}
#endif
ret = __netif_receive_skb(skb);
rcu_read_unlock();
return ret;
}
这段代码包含了两个函数,`netif_receive_skb` 和 netif_receive_skb_internal。
netif_receive_skb 是公开的API,用于处理从网络接收到的数据包。这个函数的作用是将收到的数据包传入内核网络栈进行进一步处理。它定义了一个跟踪点(tracepoint)来记录数据包接收事件,然后调用 netif_receive_skb_internal 来执行实际的处理。
netif_receive_skb_internal 是实际处理数据包的内部函数。该函数开始时通过对数据包进行时间戳检查来确定是否需要进一步处理。如果启用了泛型XDP,并且XDP程序对数据包的处理结果不是通过(XDP_PASS),则会直接返回并丢弃数据包(NET_RX_DROP),不再进一步处理。
如果启用了接收包处理软中断(RPS)配置,这是一个为多核处理系统设计的性能优化机制,它会尝试将数据包分发到合适的CPU上的后备队列中。如果没有启用RPS或者相关的处理不适用,会直接调用 __netif_receive_skb 函数来进行通常的数据包接收处理。
注意这些函数通常在软中断上下文中调用,这意味着它们不能被长时间阻塞,并且不能睡眠。因此它们通常都是快速执行的,并且需要注意并发和RPS等高级特性以获得最优的性能。在多核处理器系统中,处理网络数据包的性能至关重要,所以这些函数的设计考虑到了多核调度和效率。
二、讲解
这两个函数是Linux内核网络子系统中的一部分,它们负责处理接收到的网络数据包。
netif_receive_skb 函数
netif_receive_skb 函数是网络设备驱动收到数据包后的主要处理函数。当网络数据包(由`struct sk_buff`结构体表示)准备好从网络设备接收时,此函数被调用。
这个函数只能在软中断(softirq)上下文中被调用,并且在调用时应当开启中断。
函数返回的值通常会被忽略,但可能是以下几种:
- NET_RX_SUCCESS:代表数据包被成功处理,没有拥塞发生。
- NET_RX_DROP:代表数据包由于拥塞控制或协议层的原因被丢弃。
此函数简单地记录数据包接收事件(trace_netif_receive_skb_entry),并调用`netif_receive_skb_internal`函数来进行实际的数据包处理。
netif_receive_skb_internal 函数
netif_receive_skb_internal 是`netif_receive_skb`的内部实现,它执行实际的数据包接收处理操作。
1. 首先,检查是否需要记录时间戳(net_timestamp_check),如果需要的话,就对数据包时间戳进行处理。
2. 接着,检查是否需要进行接收路径时间戳的推迟处理(skb_defer_rx_timestamp)。如果是,将返回`NET_RX_SUCCESS`并退出。
3. 然后,如果全局性的XDP(eXpress Data Path)功能被需要,它会尝试执行XDP处理程序。XDP是一个高性能且灵活的数据包处理路径,可以运行eBPF程序来进行数据包的处理。如果XDP处理结果不是通过(XDP_PASS),则数据包将被丢弃,函数返回`NET_RX_DROP`。
4. 如果启用了接收包路由(RPS,接收包流量控制),则会尝试根据RPS逻辑确定合适的CPU来处理此数据包,如果找到,则将数据包入队到相应CPU的后端(backlog)中,接着返回相应的处理结果。
5. 如果没有应用RPS或者XDP处理结果是通过,函数会调用`__netif_receive_skb`来进行标准的网络数据包接收处理。这个过程涉及到网络协议栈的各个层级,处理如路由决策、协议分发(例如,IPv4、IPv6、ARP)等任务。
6. 最后,返回处理结果,它可能显示数据包被成功处理或者被丢弃。
以上描述的函数是网络接收路径中的关键部分,负责确保数据包被正确地从网络设备收集并按照配置的网络策略进行处理。