Linux内核中网络数据的接收

本文深入探讨Linux内核如何处理网络数据的接收,通过`budget`变量管理和`napi_poll`函数调用来优化网络包的处理。同时,`deliver_skb`函数用于将接收到的数据包传递给相应的设备。

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

1. Linux网络数据的接收始于中断,本文用wifi驱动ath10k进行分析,中断处理函数为
ath10k_pci_interrupt_handler,那么中断处理函数是如何与网卡关联?要了解这个
问题就得了解pcie接口网卡的注册流程:
->ath10k_pci_init drivers/net/wireless/ath/ath10k/pci.c
->ath10k_pci_probe
->ath10k_pci_request_irq(ar); 
->ath10k_pci_request_irq_msi(ar);
->request_irq(ar_pci->pdev->irq, ath10k_pci_interrupt_handler, ...);
至此我们将中断处理函数ath10k_pci_interrupt_handler和网卡的device结构体关联起来了。

2. 当接收数据唤醒网络中断时,中断处理函数ath10k_pci_interrupt_handler做了些什么事情?
1. 唤醒pcie设备,ath10k_pci_force_wake(ar);

2. 关pcie中断,ath10k_pci_irq_msi_fw_mask(ar),关中断的作用是为了使用NAPI polling
数据。为什么使用NAPI呢?在NAPI之前网络数据的接收模式有两种, polling方式和中
断方式, 如果只使用中断模式的话,在数据量比较大的情况下, CPU不停的进出中断,
基本上无法响应其他进程了。这种情况下使用polling模式比较好,但是polling模式不
适合数据量低的情况。所以NAPI应运而生,在高数据率的情况下使用polling模式,低数
据量的时候使用中断模式。

3. 触发软中断用来接收数据, napi_schedule(&ar->napi);
->__napi_schedule() net/core/dev.c
->__raise_softirq_irqoff(NET_RX_SOFTIRQ); kernel/softirq.c
->or_softirq_pending(1UL << nr);

3.  软中断的action的触发过程? 我们知道在2.3中设置软中断,那么软中断是如何触发的。
通过对GIC framework的分析,我们知道任何硬件中断都会触发软中断。分析过程如下:
gic_handle_irq为gic的isr, 任何一个硬件中断都会调用gic_handle_irq:
->gic_handle_irq drivers/irqchip/irq-gic.c
->handle_domain_irq
->irq_enter:arch/arm/kernel/smp.c
->irq_exit():kernel/softirq.c 
->invoke_softirq();
->__do_softirq  include/linux/interrupt.h
->while ((softirq_bit = ffs(pending)))  h->action(h);
->net_rx_action

4. 为什么会调用的net_rx_action()?而不是其他的软中断处理函数?这个就得从network
framework分析了,网络驱动在net/core/dev.c指定了net的rx和tx对应的action。 
net_dev_init() net/core/dev.c
->open_softirq(NET_TX_SOFTIRQ, net_tx_action);
->open_softirq(NET_RX_SOFTIRQ, net_rx_action);
->softirq_vec[nr].action = action;  softirq_vec[nr].action = action;
而在上文中,我们知道__napi_schedule()会设置软件中断的flag,
or_softirq_pending(1UL << nr),arm在响应gic_handle_irq()时发现net_rx_action()
对应的flag置位,因此会触发net_rx_action()


5. net_rx_action()是怎么实现接受网络数据的? 具体的code在net/core/dev.c中: 
1. 每个CPU都有一个softnet_data, softnet_data有结构体成员poll_list,
____napi_schedule的时候将napi->poll_list,挂在sd->poll_list上, code为
list_add_tail(&napi->poll_list, &sd->poll_list);

2.  遍历sd->poll_list, sd->poll_list的一个节点代表一个网卡设备,每遍历一个节点,
取出节点的内容赋值给napi_struct结构体, 并调用对应的poll函数
for (;;) 
{
struct napi_struct *n;

if (list_empty(&list)) 
{
if (!sd_has_rps_ipi_waiting(sd) && list_empty(&repoll))
return;

break;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值