首先模块加载insmod ixgbe.ko
1 | module_init(ixgbe_init_module); |
于是看pci设备的核心结构体
1 | static struct pci_driver ixgbe_driver = { |
当设备加载成功后,会执行ixgbe_probe函数
1 | static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
重点看ixgbe_init_interrupt_scheme(adapter)函数,该函数里面会初始化adapter结构体以及napi相关的东西
1 | int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter) |
到此为止,网卡设置初始化完毕
其中涉及到如下几个结构体
1 | ixgbe_adapter |
然后当我们ifconfig dev up 时,会执行dev_ops->open函数
1 | static int ixgbe_open(struct net_device *netdev) |
从上面的代码流程可以看出,最终注册的中断处理函数为ixgbe_msix_clean_rings
1 | static irqreturn_t ixgbe_msix_clean_rings(int irq, void *data) |
从上述代码中可以看,该中断处理函数仅仅作为napi的调度者
当数据包到来时,首先唤醒硬中断执行ixgbe_msix_clean_rings函数,最终napi_schedule会调用__raise_softirq_irqoff去触发一个软中断NET_RX_SOFTIRQ,然后又对应的软中断接口去实现往上的协议栈逻辑
然后看看napi 调度函数都做了些什么工作
1 | static inline void napi_schedule(struct napi_struct *n) |
NET_RX_SOFTIRQ是收到数据包的软中断信号对应的接口是net_rx_action
NET_TX_SOFTIRQ是发送完数据包后的软中断信号对应的接口是net_tx_action
1 | static void net_rx_action(struct softirq_action *h) |
于是就执行到初始化napi结构体中的poll函数,在这里为ixgbe_poll
1 | int ixgbe_poll(struct napi_struct *napi, int budget) |