Linux源码笔记-网络栈-接收流程
(1)硬中断(中断处理的前半部)
XXX_rx_interrupt
napi_schedule
_napi_schedule
_raise_softirq_irqoff(NET_RX_SOFTIRQ)
(2)软中断(中断处理的后半部)
// 通过这种共享的 <伪napi_struct> 方式使得non-napi设备很好的融入了NAPI框架,
// 使得non-napi和NAPI设备对下半部 net_rx_action() 是透明的。
// 软中断
// NET_RX_SOFTIRQ
net_rx_action
// 开始轮询
napi_poll
//////////////////////////////////////////
// 在这里调用驱动的 napi_struct->poll 函数,
// 如果驱动有支持NAPI,会定义并初始化这个poll函数,
// 对于非NAPI驱动,它默认的poll函数是process_backlog
// 对于支持NAPI的驱动,由netif_napi_add给中断注册napi_poll回调
napi_struct->poll
(2.2)软中断:对于不支持NAPI的驱动,
操作系统默认的poll函数是process_backlog
process_backlog
_netif_receive_skb
_netif_receive_skb_core
deliver_skb
packet_type->func
arp_rcv
ip_rcv
(2.3)软中断:对于支持NAPI的驱动:
(2.3.1)NAPI的Poll函数:
(a)通过netif_napi_add向操作系统注册本驱动的poll函数:
//支持NAPI
// netif_napi_add(dev, &cell->napi, gro_cell_poll, 64);
gro_cell_poll
napi_gro_receive
napi_complete
(b)BCM网卡注册的NAPI的Poll函数:
// (B) 对于支持NAPI的驱动,
// netif_napi_add(dev, &priv->napi, bcm_sysport_poll, 64)
bcm_sysport_poll
bcm_sysport_desc_rx
napi_gro_receive
napi_complete
(c)i40e网卡注册的NAPI的Poll函数:
// netif_napi_add(vsi->netdev, &q_vector->napi,i40e_napi_poll, NAPI_POLL_WEIGHT);
i40e_napi_poll
i40e_clean_rx_irq
i40e_receive_skb
napi_gro_receive
napi_complete
(d)tg3网卡注册的NAPI的Poll函数:
// (B) 对于支持NAPI的驱动,
// netif_napi_add(tp->dev, &tp->napi[0].napi, tg3_poll, 64)
tg3_poll
tg3_poll_work
tg3_rx
napi_gro_receive
napi_complete
(2.3.2)NAPI的组装函数:
它主要是将分片的skb进行组装,然后形成一个新的skb
如果没有gro,则小的段会被一个个送到协议栈,
有了gro之后,就会在接收端将tso切好的数据包组合成大包再传递给协议栈。
然后GRO什么时候会将数据feed进协议栈呢,这里会有两个退出点,
一个是在napi_skb_finish里,他会通过判断__napi_gro_receive的返回值,来决定是需要将数据包立即feed进协议栈还是保存起来,
一个是当napi的循环执行完毕时,也就是执行napi_complete的时候,
napi_gro_receive
dev_gro_receive
packet_offload->callbacks.gro_receive
inet_gro_receive
net_offload->callbacks.gro_receive
//如果本次NAPI已经完毕,是时候执行flush GRO packet 了,
//那么napi_gro_complete 调用netif_receive_skb_internal
napi_gro_complete
netif_receive_skb_internal
//一旦 dev_gro_receive 完成,napi_skb_finish 就会被调用,
// (2)如果当dev_gro_receive 返回 GRO_NORMAL的时候
// 那么 napi_skb_finish 会调用 netif_receive_skb_internal
napi_skb_finish
netif_receive_skb_internal
(3)网络栈
(2.3.2)skb组装完毕入队列:
// (A) 如果 RPS 被启用,那么会调用enqueue_to_backlog
enqueue_to_backlog
softnet_data->input_pkt_queue
// (B) 如果 RPS 没启用,那么会调用__netif_receive_skb,
_netif_receive_skb
_netif_receive_skb_core
deliver_skb
packet_type->func
ip_rcv
net_device->rx_handler
br_handle_frame
bond_handle_frame
(2.3.3)skb组装完毕入队列:5.10内核
netif_receive_skb
netif_receive_skb_internal
__netif_receive_skb
__netif_receive_skb_one_core
__netif_receive_skb_core
deliver_skb
# 本地协议栈处理
packet_type->func
ip_rcv
sk_buff->dev->rx_handler
# 桥处理
br_handle_frame
////////////////////////////////////////////////
__netif_receive_skb_core函数主要有几个处理:
(1) vlan报文的处理,主要是循环把vlan头剥掉;
(2) 交给 net_device->rx_handler 处理,例如OVS、linux bridge等;
(3) ptype_all处理,例如抓包程序、raw socket等;
(4) ptype_base处理,交给协议栈处理,例如ip、arp、rarp等;
(2.3.4)桥处理:5.10内核
br_handle_frame
br_handle_frame_finish
br_forward
br_forward_finish
br_dev_queue_push_xmit
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类