网卡驱动和队列层中的数据包接收Linux TCPIP协议栈笔记.docVIP

  • 2
  • 0
  • 约1.46万字
  • 约 13页
  • 2019-12-23 发布于湖北
  • 举报

网卡驱动和队列层中的数据包接收Linux TCPIP协议栈笔记.doc

原文地址: /viewthread.php?tid=14extra=page%3D1 Linux TCP/IP协议栈笔记 网卡驱动和队列层中的数据包接收 作者:kendo Kernel:2.6.12 文章对于我们理解TCP发送数据包以及收取数据包非常有帮助。 四、网卡的数据接收 内核如何从网卡接受数据,传统的经典过程: 引用 1、数据到达网卡; 2、网卡产生一个中断给内核; 3、内核使用I/O指令,从网卡I/O区域中去读取数据; 我们在许多网卡驱动中,都可以在网卡的中断函数中见到这一过程。 但是,这一种方法,有一种重要的问题,就是大流量的数据来到,网卡会产生大量的中断,内核在中断上下文中,会浪费大量的资源来处理中断本身。所以,一个问题是,“可不可以不使用中断”,这就是轮询技术,所谓NAPI技术,说来也不神秘,就是说,内核屏蔽中断,然后隔一会儿就去问网卡,“你有没有数据啊?”?? 从这个描述本身可以看到,哪果数据量少,轮询同样占用大量的不必要的CPU资源,大家各有所长吧,呵呵?? OK,另一个问题,就是从网卡的I/O区域,包括I/O寄存器或I/O内存中去读取数据,这都要CPU去读,也要占用CPU资源,“CPU从I/O区域读,然后把它放到内存(这个内存指的是系统本身的物理内存,跟外设的内存不相干,也叫主内存)中”。于是自然地,就想到了DMA技术——让网卡直接从主内存之间读写它们的I/O数据,CPU,这儿不干你事,自己找乐子去: 引用 1、首先,内核在主内存中为收发数据建立一个环形的缓冲队列(通常叫DMA环形缓冲区)。 2、内核将这个缓冲区通过DMA映射,把这个队列交给网卡; 3、网卡收到数据,就直接放进这个环形缓冲区了——也就是直接放进主内存了;然后,向系统产生一个中断; 4、内核收到这个中断,就取消DMA映射,这样,内核就直接从主内存中读取数据; ——呵呵,这一个过程比传统的过程少了不少工作,因为设备直接把数据放进了主内存,不需要CPU的干预,效率是不是提高不少? 对应以上4步,来看它的具体实现: 1、分配环形DMA缓冲区 Linux内核中,用skb来描述一个缓存,所谓分配,就是建立一定数量的skb,然后把它们组织成一个双向链表; 2、建立DMA映射 内核通过调用 dma_map_single(struct device *dev,void *buffer,size_t size,enum dma_data_direction direction) 建立映射关系。 struct device *dev,描述一个设备; buffer:把哪个地址映射给设备;也就是某一个skb——要映射全部,当然是做一个双向链表的循环即可; size:缓存大小; direction:映射方向——谁传给谁:一般来说,是“双向”映射,数据在设备和内存之间双向流动; 对于PCI设备而言(网卡一般是PCI的),通过另一个包裹函数pci_map_single,这样,就把buffer交给设备了!设备可以直接从里边读/取数据。 3、这一步由硬件完成; 4、取消映射 dma_unmap_single,对PCI而言,大多调用它的包裹函数pci_unmap_single,不取消的话,缓存控制权还在设备手里,要调用它,把主动权掌握在CPU手里——因为我们已经接收到数据了,应该由CPU把数据交给上层网络栈; 当然,不取消之前,通常要读一些状态位信息,诸如此类,一般是调用 dma_sync_single_for_cpu() 让CPU在取消映射前,就可以访问DMA缓冲区中的内容。 关于DMA映射的更多内容,可以参考《Linux设备驱动程序》“内存映射和DMA”章节相关内容! OK,有了这些知识,我们就可以来看e100的代码了,它跟上面讲的步骤基本上一样的——绕了这么多圈子,就是想绕到e100上面了,呵呵! 在e100_open函数中,调用e100_up,我们前面分析它时,略过了一个重要的东东,就是环形缓冲区的建立,这一步,是通过 e100_rx_alloc_list函数调用完成的: static int e100_rx_alloc_list(struct nic *nic) 1. { 2. struct rx *rx; 3. unsigned int i, count = nic-params.rfds.count; 4. 5. nic-rx_to_use = nic-rx_to_clean = NULL; 6. nic-ru_running = RU_UNINITIALIZED; 7. 8. /*结构struct rx用来描述一个缓冲区节点,这里分配了count个*/ 9. if(!(nic-rxs = kmalloc(sizeof(struct rx) * count, G

文档评论(0)

1亿VIP精品文档

相关文档