深入理解Linux网络技术内幕学习笔记第十章:帧的接收

Linux驱动程序通知内核帧已经接收的方式有两种:
NAPI机制(新的):
NAPI混合了中断事件和轮询。
为了处理驱动程序使用NAPI接口的设备,有四个新字段添加到net_device结构中,以供NET_RX_SOFTIRQ软IRQ使用:
    poll:此函数用于把缓冲区从输入队列中退出。该队列是使用NAPI机制的设备的私有队列。
    poll_list:设备队列,其中的设备就是入口队列中有新帧等待被处理的设备。此列表中的设备处于中断功能关闭的状态,而内核当前正在予以轮询。
    quota:整数,表示poll函数一次可以从队列中退出的缓冲区的最大数目。其值的增加以weight为单位。
    weight:
使用NAPI的设备会对这四个字段及其他字段初始化。
net_rx_action是与NET_RX_SOFTIRQ标识相关联的函数,当它被触发时,会浏览列表中处于轮询状态的设备,然后为每个设备调用相关联的poll函数来处理入口队列中的帧。
从设备驱动的角度看,NAPI和非NAPI只有两点区别:首先,NAPI驱动必须提供一个poll方法。其次,非NAPI调用netif_rx,NAPI调用_ _netif_rx_schedule(内核提供了一个包裹函数netif_rx_schedule )。这两种驱动都会把输入设备排入轮询列表poll_list(非NAPI的poll_list指的是softnet_data结构中的字段,NAPI指的是net_device结构中的字段),然后准备执行软IRQ关联的处理函数。最后再由net_rx_action予以处理。
另外需要注意的是,在两种情况下传给_ _ netif_rx_schedule的net_device结构,非NAPI使用的是cpu存储的softnet_data结构中的backlog_dev字段,NAPI使用的是涉及它们自己的net_device结构。
netif_rx(旧的):多数Linux设备驱动程序仍然使用这种方法
netif_rx通常是在中断环境下被驱动调用。因此,netif_rx启动时,会关闭cpu的中断事件。netif_rx的主要任务如下(发生在中断处理中的上半部):
    对sk_buff数据结构的一些字段初始化
    把已接收的帧存储到cpu的私有输入队列,然后触发相关联的软IRQ NET_RX_SOFTIRQ通知内核。
    更新有关拥塞等级的统计数据。
Netpoll是一个通用架构,可通过轮询NIC而传输或接收帧,把中断事件的需求删除掉。
netif_rx函数会先把函数启用时间(也是帧接收到缓冲区的时间)保存到sk_buff结构的stamp字段。net_device结构中也有一个时间,表示帧到达设备的时间。
netif_rx中更新的统计数据是对于一个cpu来说的,net_device结构中priv字段所表示的统计数据是设备驱动统计的,针对一个设备来说的。
当设备驱动使用NAPI时,由驱动实现拥塞控制机制,因为入口帧会被放在NIC的内存或者驱动控制的receiving ring内,内核无法追踪流量。当设备不使用NAPI时,帧被添加到各个cpu的队列中,内核就会追踪队列的拥塞情况。
net_rx_action函数:
net_rx_action用于处理进来的帧的下一个函数。当驱动通知内核帧已经接收时会被触发执行。帧可以在两个地方等待被net_rx_action处理:
    一个多设备共享的CPU专用队列:非NAPI设备的中断处理例程,调用netif_rx把帧放入CPU的softnet_data->input_pkt_queue。
    设备内存:NAPI驱动所用的poll方法会直接从设备内存取出帧(或设备驱动程序的接收环)。
net_rx_action会浏览poll_list列表,为每个设备启动相关联的poll函数,直到poll_list中没有设备了,或者执行时间太久了,或者从队列中退出及处理的帧达到上限时,net_rx_action才会退出。退出时,若队列中还有数据没有处理完,NET_RX_SOFTIRQ软IRQ会被再次调度,稍后将启用net_rx_action处理剩余的数据。
注意,net_rx_action执行时,中断功能是开启的(中断处理例程的下半部),但是在操作设备列表poll_list做轮询时(即访问softnet_data结构实例时),会关闭中断功能。
积压的处理:
net_device数据结构的poll函数会由net_rx_action执行,以处理设备的积压队列。对于不使用NAPI的设备而言,积压的处理默认使用process_backlog。
netif_receive_skb函数:
poll函数调用netif_receive_skb函数帮忙辅助处理入口帧
netif_receive_skb的三个主要任务:
    把帧的副本传给协议分流器。
    把帧的副本传给skb->protocol关联的L3协议处理函数。
    负责此层必须处理的一些功能,如桥接。
skb_bond函数负责将sk_buff中接收接口改成bond群组中的主设备。
如果桥接代码或入口流量控制代码没有消化该帧,则帧会传给L3协议处理函数。此时,接收部分已经完成,之后就是L3协议处理函数决定该如何处理该帧。内核可以从L3的目的地址确定该封包是传给上层应用还是转发。
netif_receive_skb会检查是否有netpoll客户想要消化该帧。流量控制通常用于出口队列。新版本的内核也可以在入口流量上配置过滤,依据配置,ing_filter可以决定输入缓冲区是要被丢弃还是进一步处理。
diverter允许内核改变接收帧的L2目的地址。
除了diverter ,另一个L2功能Bridging(桥接)也会影响帧的命运。net_device结构中的net_bridge_port用于存储桥接端口的信息。当NIC开启了桥接功能时,内核只会看L2报头,此时,内核唯一用到L3信息的地方是防火墙相关的信息。因为net_rx_action代表设备驱动和L3协议处理例程的边界,所以此函数中必须处理桥接功能。
简单总结一哈:网卡接收到帧后,产生硬件中断,执行中断处理例程,中断处理分为上下两个部分,上半部分是必须即使处理的(如将帧拷贝到sk_buff等),且处理过程中无法被中断,cpu无法被抢占,netif_rx(旧)和NAPI(新)就是负责这部分,然后通知内核帧已经接收,等待处理。下半部主要是net_rx_action函数负责处理接收到的帧。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值