Linux协议栈链路层处理

基于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);
   .......
}

你可能感兴趣的:(linux,接口,数据包,placed)