阅读169 返回首页    go 阿里云 go 技术社区[云栖]


网络子系统21_传输接收软中断的触发

//参考 深入理解linux网络技术内幕

//设备接收数据的调度
//在由驱动程序提供的数据接收中断中:
//	1.非napi设备使用netif_rx向上传递skb
//	2.napi设备使用netif_rx_schedule


//设备发送数据的调度
//	调度只针对具有队列规则的设备,在qdisc_run中如果无法获得xmit_lock锁,则通过规则队列重新入队skb,在net_tx_action中,获取queue_lock失败,调度设备
//	对于不使用队列规则的设备,直接通过dev_queue_xmit调用驱动的hard_start_xmit完成传输
//调度发生的路径
//	dev_queue_xmit->qdisc_run->netif_schedule
//	net_tx_action->netif_schedule

//调度设备发送数据,将设备链接到per-cpu的softnet_data->output_queue中,触发软中断
1.1 static inline void netif_schedule(struct net_device *dev)
{
	//如果设备没有关闭传输
	if (!test_bit(__LINK_STATE_XOFF, &dev->state))
		//执行实际的调度设备操作
		__netif_schedule(dev);
}

//netif_schedule->__netif_schedule
1.2 static inline void __netif_schedule(struct net_device *dev)
{
	//设备没有被调度
	if (!test_and_set_bit(__LINK_STATE_SCHED, &dev->state)) {
		unsigned long flags;
		struct softnet_data *sd;
		//关本cpu中断
		local_irq_save(flags);
		sd = &__get_cpu_var(softnet_data);
		//将设备挂在到softnet_data的output_queue上
		dev->next_sched = sd->output_queue;
		sd->output_queue = dev;
		//触发传输软中断
		raise_softirq_irqoff(NET_TX_SOFTIRQ);
		local_irq_restore(flags);
	}
}


//napi、非napi接收数据时的调度区别



                         

//非napi设备接收中断中使用,将skb向上传输
2.1 int netif_rx(struct sk_buff *skb)
{
	int this_cpu;
	struct softnet_data *queue;
	unsigned long flags;
	//处理netpoll
	if (skb->dev->netpoll_rx && netpoll_rx(skb)) {
		kfree_skb(skb);
		return NET_RX_DROP;
	}
	//更新数据接收到的时间戳
	if (!skb->stamp.tv_sec)
		net_timestamp(&skb->stamp);

	//关中断
	local_irq_save(flags);
	this_cpu = smp_processor_id();
	queue = &__get_cpu_var(softnet_data);//获取当前cpu的softnet_data

	__get_cpu_var(netdev_rx_stat).total++;//增加收到数据包的统计变量
	if (queue->input_pkt_queue.qlen <= netdev_max_backlog) {//接收队列有空闲空间
		if (queue->input_pkt_queue.qlen) {
			if (queue->throttle)//队列处于拥塞状态
				goto drop;

enqueue:
			dev_hold(skb->dev);
			__skb_queue_tail(&queue->input_pkt_queue, skb);//挂载skb到非NAPI设备专用的输入队列

			local_irq_restore(flags);//开中断
			return queue->cng_level;//返回拥塞等级
		}

		if (queue->throttle)//输入队列中没有skb,但是上次被标记为拥塞
			queue->throttle = 0;//重新开启数据接收

		netif_rx_schedule(&queue->backlog_dev);//运行到此处,说明输入队列中的skb个数为0,调度积压设备,入列skb
		goto enqueue;
	}
	//当发生拥塞时,会暂停数据的接收,直到input_pkt_queue为空之后,才重新开启数据的接收
	if (!queue->throttle) {
		queue->throttle = 1;
		__get_cpu_var(netdev_rx_stat).throttled++;
	}

drop:
	__get_cpu_var(netdev_rx_stat).dropped++;
	local_irq_restore(flags);

	kfree_skb(skb);
	return NET_RX_DROP;
}

//napi设备接收中断中使用,链接设备到softnet->poll_list上
3.1 static inline void netif_rx_schedule(struct net_device *dev)
{
	if (netif_rx_schedule_prep(dev))//检测设备是否已经被调度
		__netif_rx_schedule(dev);//调度设备
}


3.2 static inline void __netif_rx_schedule(struct net_device *dev)
{
	unsigned long flags;

	local_irq_save(flags);
	dev_hold(dev);
	list_add_tail(&dev->poll_list, &__get_cpu_var(softnet_data).poll_list);//将设备链接到softnet_data->poll_list上
	if (dev->quota < 0)
		dev->quota += dev->weight;//分配设备此次调度的配置
	else
		dev->quota = dev->weight;
	__raise_softirq_irqoff(NET_RX_SOFTIRQ);//触发软中断
	local_irq_restore(flags);
} 



最后更新:2017-04-03 15:22:11

  上一篇:go 网络子系统28_桥接ioctl
  下一篇:go 深入理解JVM内幕:从基本结构到Java 7新特性