代码学习-Linux内核网卡收包过程(NAPI)

本文通过RealTek8169/8168/8101网卡驱动代码分析Linux内核网卡收包过程,包括驱动初始化、probe、中断处理、软中断线程ksoftirqd和内核协议栈的接收。重点讲解了从设备注册到中断处理再到报文接收的完整路径,深入理解网络驱动工作原理。

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

 本文通过学习RealTek8169/8168/8101网卡的驱动代码(drivers/net/r8169.c),梳理一下Linux下网卡的收包过程。

在下水平相当有限,有不当之处,还请大家斧正^_^

 

驱动的初始化

如下的rtl8169_init_module函数是此驱动的初始化代码,此函数只干了一件事,就是向内核注册一个pci驱动rtl8169_pci_driver。

static int __init rtl8169_init_module(void)

{

        returnpci_register_driver(&rtl8169_pci_driver);

}

 

rtl8169_pci_driver驱动的定义如下。

static struct pci_driver rtl8169_pci_driver= {

        .name               = MODULENAME,

        .id_table  = rtl8169_pci_tbl,

        .probe              = rtl8169_init_one,

        .remove            = __devexit_p(rtl8169_remove_one),

        .shutdown       = rtl_shutdown,

        .driver.pm        = RTL8169_PM_OPS,

};

 

.id_table成员是一个驱动程序支持的全部设备列表。对于rtl8169_pci_driver,id_tabl就是b rtl8169_pci_tbl了,其内容如下。可见此驱动支持多种不同型号的网卡芯片。

 

static struct pci_device_idrtl8169_pci_tbl[] = {

        {PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8129),0, 0, RTL_CFG_0 },

        {PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8136),0, 0, RTL_CFG_2 },

        {PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167),0, 0, RTL_CFG_0 },

        {PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168),0, 0, RTL_CFG_1 },

        {PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169),0, 0, RTL_CFG_0 },

        {PCI_DEVICE(PCI_VENDOR_ID_DLINK,       0x4300),0, 0, RTL_CFG_0 },

        {PCI_DEVICE(PCI_VENDOR_ID_AT,               0xc107),0, 0, RTL_CFG_0 },

        {PCI_DEVICE(0x16ec,                         0x0116),0, 0, RTL_CFG_0 },

        {PCI_VENDOR_ID_LINKSYS,  0x1032,   PCI_ANY_ID, 0x0024, 0, 0, RTL_CFG_0 },

        {0x0001,        0x8168,         PCI_ANY_ID, 0x2410, 0, 0, RTL_CFG_2 },

        {0,},

};

 

需要注意到,驱动中还有如下一行代码。

MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl);

这个宏貌似是给rtl8169_pci_tbl变量起了一个别名__mod_pci_device_table。可见__mod_pci_device_table是pci设备驱动中的一个统一的符号名。他包含了此驱动支持的全部设备的列表。

这是干什么的呢?这时解释一下。

如果此驱动被编译到了内核中,或者此驱动已经被加载到内核中。那么这一句话就没什么作用了。因为内核随时可以根据rtl8169_pci_driver中的信息,来判断某一设备是否匹配此驱动。代码见pci_match_device函数。

但是,如果此驱动被编译成了一个模块文件r8169.ko,并且没有被加载到内核中(正常情况下,大量的设备驱动都应该是被编译成模块的,并且都是不加载到内核中的。机器上电时,根据扫描到的设备,动态加载相应的驱动模块。不然的话,如果各种驱动都加载到内核中,那内核就太臃肿了)。此时,如果内核扫描到了一个pci设备,就得加载相应的驱动模块文件。但内核只掌握了此设备的类似Vendorand device ID这样的信息,如何将这种信息对应到具体的驱动模块文件r8169.ko呢。这时候MODULE_DEVICE_TABLE这句话就发挥作用了。具体细节,可以参考udev与modprobe等相关知识。

 

这里顺便多说两句,当一个pci驱动被加载到内核中时(见调用链pci_register_driver ->__pci_register_driver -> driver_register ->bus_add_driver ->driver_attach),或者当内核发现一个新设备时(见调用链device_add->bus_probe_device->device_attach),

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值