概述
报文的接收是整个协议栈的入口,负责从网卡中把报文接收并送往内核协议栈相应协议处理模块处理。
报文的接收方法主要分为两种
一种是网卡产生中断,通知内核进行接收报文。一次中断接收一个报文。在中断处理程序中把报文从硬件缓存中拷贝到内存中,并把报文加入到协议栈中对应的入口队列中,中断退出时调用收包软中断来从相应队列来读取报文进行处理。这种方式优点是内核对报文响应较快,在网卡上 有少量报文时效果较好。这样如果网卡有大量报文的话,会产生大量中断。中断会不断打断处理报文的软中断,这样先前的报文来不及处理,总是被打断,队列里的报文大量堆积导致不能被及时处理,导致报文性能下降。
另一种是中断加轮询的方式进行接收报文的。当一个报文到来时,产生中断通知内核,注册的中断处理程序首先禁止网卡的中断,内核开始轮询的从网卡硬件缓存或网卡硬件管理的内存队列中读取报文并处理,直到报文读完或超出了设置的允许读取最大报文个数,轮询函数停止处理报文。如果这次轮询处理完了全部报文,并接着使能网卡中断。如果轮询没有处理完全部报文,这时就重新调度软中断,等下次软中断被调度到后继续轮询处理报文。这样是为了防止轮询独占CPU时间。以后重复这样的接收报文步骤。这样内核处理一次中断可以处理多个报文,这样就避免了产生大量中断造成的系统开销。但支持这样的操作的网卡必须支持硬件能自动把报文存入内存中,或硬件缓存足够大。否则当一次轮询结束后并没有处理完全部的报文时,到下次软中断被调度到开始轮询的这段时间里,当网卡硬件内部的缓存满后会产生丢包。
Linux 提供对两种报文接收方式的支持,供不同网卡驱动来用。因为对处理网络流量不是很大的网卡没必要支持自动把报文存入内存或硬件缓存很大,而网络设备上对网卡在这方面的功能要求较高。因此第一种方式还是有存在的必要的。在本文章把第一种称为旧的方式(旧是相对于NAPI来说的),第二种方法linux内核中称为NAPI方式。
报文的接收步骤预览:
一、旧的接收过程
1、当网卡中断产生后,内核的中断处理部分会根据网卡驱动注册的中断号找到相应网卡 驱动中的中断处理函数。
2、 中断处理函数首先禁用网卡的接收报文中断。
3、接着负责在内存中申请一个skb,把网卡硬件缓存中的报文拷贝到skb中。初始化skb中的一些字段,根据报文内容给skb->protocol字段赋值。例如ip报文会赋为0x0800
4、接着调用netif_rx把skb 放入本地cpu的接收队列。
5、 接着使能网卡收包中断。中断处理函数退出。在中断处理函数退出时会调度报文接收软中断进行处理cpu上的接收队列中的报文。
从网卡硬件缓存中把报文拷贝到内存放在硬件中断处理中做,把协议栈处理报文的工作放在软中断做,这样提高了对硬件中断的响应速度。
二 、NAPI方式接收:
1、当网卡中断产生时,找到网卡驱动中中断处理函数。
2、中断处理函数禁用网卡接收报文中断。
3、把内核中代表网卡的net_dev 挂到本地cpu的pool队列上。表示网卡上有报文要处理。
4、接着调度报文接收的软中断来处理该cpu上挂着的dev.
5、在软中断中会找到本地cpu上pool队列上的dev,调用相应网卡驱动的轮询函数来处理报文。
6、网卡驱动的轮询函数会读取报文,初始化skb,调用netif_receive_skb把报文直接送到协议栈进行处理。每次轮询处理的报文个数有一个限制,防止轮询函数长时间占用cpu。如果读取完全部报文,就使能网卡收报文的中断。中断返回。如果处理的报文到了限制个数,但没处理完全部的报文,就把dev再次挂到本地cpu的pool链表上,不用使能中断。调度报文接收软中断接着处理。一个报文会在轮询函数中走完协议栈并被处理完成,不用再被缓存到相应的队列中。
NAPI的另一个优点是设备处理更为公平,因为软中断顺序执行每个需要处理的设备的轮询函数,每个轮询函数执行时间是有限制的,允许执行时间到了后就会执行下一个设备的轮询函数。这样就保证负载低的和负载高的设备被处理的机会一样。
本文出自 “耀洋的博客” 博客,请务必保留此出处http://yaoyang.blog.51cto.com/7657153/1262489
最后
以上就是如意溪流为你收集整理的报文的接收方式(linux网络子系统学习 第二节 )的全部内容,希望文章能够帮你解决报文的接收方式(linux网络子系统学习 第二节 )所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复