基于Linux3.3
整个过程不考虑2.6.35引入的RPS,另一篇文档会单独介绍RPS
数据包接收
首先介绍下,softnet_data结构,这是一个每CPU变量,数据包的收发都会使用该结构。
/*
* Incoming packets are placed on per-cpu queues
*/
struct softnet_data {
struct Qdisc *output_queue;
struct Qdisc **output_queue_tailp;
// 需要轮询的设备列表,NAPI时挂接的是&adapter->napi,No-NAPI是挂接softnet_data->backlog,
// 挂接backlog是为了模拟NAPI的情况,使用相同的一套API接口
struct list_head poll_list;
// 完成发包后需要释放的skb入队,用于在软中断中释放skb。主要是中断需要快速返回,而释放操作耗时。
struct sk_buff *completion_queue;
// 这个队列是32以后加上的,原来只有input_pkt_queue一个队列,在后半段处理时,直接遍历
// input_pkt_queue进行处理。修改后则先用process_queue接管
// input_pkt_queue, 清空input_pkt_queue,然后循环处理process_queue的数据报文。当process_queue
// 处理完成后会继续检查input_pkt_queue,直到没有报文需要继续处理。这样其他核来包时可以在当前核上
// 直接入队,大大减少锁冲突的几率
struct sk_buff_head process_queue;
/* stats *///一些统计状态信息
unsigned int processed;
unsigned int time_squeeze;
unsigned int cpu_collision;
unsigned int received_rps;
#ifdef CONFIG_RPS // Linux 2.6.35开始引入RPS, 分析RPS时单独介绍
struct softnet_data *rps_ipi_list;
/* Elements below can be accessed between CPUs for RPS */
struct call_single_data csd ____cacheline_aligned_in_smp;
struct softnet_data *rps_ipi_next;
unsigned int cpu;
unsigned int input_queue_head;
unsigned int input_queue_tail;
#endif
// 丢包数目的统计
unsigned dropped;
// No-NAPI的情况下,数据包在网卡中断处理时将数据包放入该队列,具体见process_queue的介绍
struct sk_buff_head input_pkt_queue;
// No-NAPI的情况下,将backlog链入softnet_data的poll_list中,轮询时找到该默认的结构
struct napi_struct backlog;
};
以E1000e-1.2.10源码介绍
// E1000e模块的入口
module_init(e1000_init_module);
/**
* e1000_init_module - Driver Registration Routine
* e1000_init_module is the first routine called when the driver is
* loaded. All it does is register with the PCI subsystem.
**/
static int __init e1000_init_module(void)
{
.......
// PCI设备注册,注册的过程,我们后续单独分析
// 对于注册成功设备,系统启动时,PCI总线开始扫描所有连接在其上面的设备,并寻找相关驱动。
// 在e1000_driver结构中,有设备探测的回调接口,供PCI层调用。这个函数大约在400行左右,完成了非常
// 多的初始化工作,net_device结构就是在probe函数中完成,该结构包括了设备接口的操作集,mac地址等N
// 多的信息。
ret = pci_register_driver(&e1000_driver);
.......
}
static int __devinit e1000_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
.......
// 注册net_device结构
err = register_netdev(netdev);
.......
}
ToDo...
阅读(2684) | 评论(0) | 转发(4) |