网络子系统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);
	...
}

上一篇:this关键字与构造器转发


下一篇:用R读取PDF并进行数据挖掘