网卡分析

E1000

首先E1000是一个PCI设备,驱动初始化的时候(module_init),会调用pci_register_driver,pci_register_driver的结构体参数包含一个probe函数指针,指向e1000_probe。probe函数用于探测到指定设备时调用(参考PCI驱动编写)。

e1000_probe中会给net_device结构体的netdev_ops赋值。并指定NAPI的poll函数为e1000_clean函数

static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
...................
    netdev->netdev_ops = &e1000_netdev_ops;
...................
    netif_napi_add(netdev, &adapter->napi, e1000_clean, 64);
...................
}

e1000_netdev_ops中包含一个open函数指针,指向e1000_open函数,其会调用e1000_request_irq注册e1000网卡中断,该函数进一步调用request_irq进行实际的注册

int e1000_open(struct net_device *netdev)
{
...................
    err = e1000_request_irq(adapter);   
...................
}

static int e1000_request_irq(struct e1000_adapter *adapter)
{
...................
	irq_handler_t handler = e1000_intr;
...................
	err = request_irq(adapter->pdev->irq, handler, irq_flags, netdev->name,netdev);
...................
	return err;
}

可以看到,e1000的实际中断处理函数是e1000_intr。(可以总结到,当我们要找到一个设备的中断处理程序时,直接搜索源代码中的request_irq函数)

e1000_intr:关闭当前网卡中断,然后开启NET_RX_SOFTIRQ软中断(NAPI)。

网卡相关软中断

软中断的注册函数为open_softirq,其中网卡相关的软中断有:NET_TX_SOFTIRQ,NET_RX_SOFTIRQ

static int __init net_dev_init(void)
{
...................
	open_softirq(NET_TX_SOFTIRQ, net_tx_action);
	open_softirq(NET_RX_SOFTIRQ, net_rx_action);
...................
}

net_rx_action会调用e1000注册的poll函数e1000_clean(参考e1000_probe中的netif_napi_add函数)

向上传递到协议栈的过程

e1000_clean 会进一步调用 e1000_clean_rx_irq函数。该函数会从网卡接收环形队列中,提取收到的数据包,构造成sk_buff结构,然后调用e1000_receive_skb向上传递到协议栈处理

e1000_receive_skb-->napi_gro_receive-->napi_skb_finish-->netif_receive_skb_internal-->__netif_receive_skb-->__netif_receive_skb_one_core-->__netif_receive_skb_core

原文地址:https://www.cnblogs.com/r1ng0/p/12488728.html