閱讀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新特性