网络子系统19_积压设备
// 1.积压设备的目的: // napi设备,非napi设备同一处理接口,linux为所有不使用napi的驱动程序,提供了一个虚拟设备,叫做积压设备。 // 2.与积压设备有关的数据结构: // 2.1 每个cpu都有一个积压设备,保存在softnet_data->backlog_dev // 2.2 每个cpu都有一个积压设备的输入队列,保存在softnet_data->input_pkt_queue,所有非napi设备的入口skb,均挂载到此队列。 // 2.3 内核为积压设备的提供poll函数,process_backlog // 积压设备的poll函数 // 调用路径:net_rx_action->process_backlog // 参数: // backlog_dev,积压设备 // budget,函数此次运行可以处理的skb配额 // 返回值: // <0 , 表明设备还有待处理的入口帧,此时设备仍然在poll_list中,且设备处于关中断状态 // =0 , 表明设备已经处理完所有的入口帧,此时设备已经从poll_list中删除,可接收重新调度,设备中断已开启 // 函数主要任务: // 1.函数运行不能超过1个jiffies,处理的skb不能超过配额 // 2.在关中断的情况下,从softnet->input_pkt_queue取下入口skb,后开中断 // 2.1 如果有入口skb // 2.1.1 通过netif_receive_skb向上层协议传递skb // 2.1.2 递减入口设备的引用计数 // 2.2 如果在运行时间不足1个jiffies,并且没有超过配额的情况下,处理完了入口队列的所有skb // 2.2.1 更新设备的可用配额 // 2.2.2 由于已经没有入口数据,因此将挤压设备从调度队列poll_list上取下来 // 2.2.3 清除积压设备的调度标志,表示设备可以接收下一次调度 // 2.2.4 如果之前入口队列满,被设置了throttle,则在入口队列为空时,清除throttle // 注:在入口队列满,设置了throttle,之后的入口数据都会被丢弃,直到入口队列为空,清除throttle之后,才开始重新接收入口数据。 1.1 static int process_backlog(struct net_device *backlog_dev, int *budget) { int work = 0; //此次调用可以处理的skb为 设备剩余配额,传入的配置中的较小者 int quota = min(backlog_dev->quota, *budget); struct softnet_data *queue = &__get_cpu_var(softnet_data); unsigned long start_time = jiffies; for (;;) { struct sk_buff *skb; struct net_device *dev; //关闭本cpu中断,因为input_pkt_queue可能会在中断中被修改 local_irq_disable(); //从input_pkt_queue上退出一个skb skb = __skb_dequeue(&queue->input_pkt_queue); if (!skb) goto job_done; //开中断 local_irq_enable(); dev = skb->dev; //将skb向上传递 netif_receive_skb(skb); //递减接收此skb的dev的引用计数 dev_put(dev); //消费流量个数-1 work++; //此函数运行时间应该 < 1 jiffies if (work >= quota || jiffies - start_time > 1) break; } //将设备的配额减去实际消费的流量个数 backlog_dev->quota -= work; //将打算让设备消费的流量个数中减去实际消费的流量个数 *budget -= work; return -1; //表示接收队列为空 job_done: backlog_dev->quota -= work; *budget -= work; //将积压设备从poll_list上删除 list_del(&backlog_dev->poll_list); smp_mb__before_clear_bit(); //清除积压设备__LINK_STATE_RX_SCHED标识,表示积压设备重新可以接收调度 netif_poll_enable(backlog_dev); //如果此cpu的输入队列已经关闭,开启输入队列 if (queue->throttle) queue->throttle = 0; //开本cpu中断 local_irq_enable(); return 0; } // 对积压设备的调度 // 调用路径 : 非napi设备的接收中断->netif_rx 2.1 int netif_rx(struct sk_buff *skb) { ... netif_rx_schedule(&queue->backlog_dev); ... }
最后更新:2017-04-03 15:22:09