閱讀399 返回首頁    go 阿裏雲 go 技術社區[雲棲]


網絡子係統22_隊列規則傳輸接口

//	調用路徑:
//		1.dev_queue_xmit->qdisc_run
//		2.net_tx_action->qdisc_run

//	對於dev->tx_queue_len !=0 的設備,都會有一個與之關聯的隊列規則,按照隊列規則,調用dev->hard_start_xmit

1.1 static inline void qdisc_run(struct net_device *dev)
{
	//設備傳輸隊列沒有被關閉,即__LINK_STATE_XOFF沒有被設置
	//結合規則隊列完成傳輸
	while (!netif_queue_stopped(dev) && qdisc_restart(dev) < 0);
}


//	結合設備關聯的隊列規則,完成數據傳輸
//	調用路徑:qdisc_run->qdisc_restart

//	返回值:	=0  - queue is empty.
//			>0  - queue is not empty, but throttled.
//			<0  - queue is not empty. Device is throttled, if dev->tbusy != 0.

//	函數流程:
//		1.使用隊列規則出隊skb
//		2.對dev->xmit_lock加鎖
//		3.檢測死鎖與衝突;
//			3.1 死鎖:鎖已被占用,占用者為本cpu,釋放skb,返回
//			3.2 衝突:鎖被占用,非本cpu,重入隊skb,重調度設備
//		4.設置鎖的擁有者為本cpu
//		5.對dev->queue_lock解鎖
//		6.向ETH_P_ALL類型l3協議傳遞此skb
//		7.通過驅動程序hard_start_xmit完成傳輸
//		8.對dev->queue_lock加鎖
//		9.對dev->xmit_lock解鎖
1.2 int qdisc_restart(struct net_device *dev)
{
	//與設備相關的隊列規則
	struct Qdisc *q = dev->qdisc;
	struct sk_buff *skb;

	//從規則隊列出隊skb
	if ((skb = q->dequeue(q)) != NULL) {
		//驅動特性:NETIF_F_LLTX,表明驅動在被調用hard_start_xmit時不需要上鎖
		unsigned nolock = (dev->features & NETIF_F_LLTX);

		if (!nolock) {//需要上鎖
			if (!spin_trylock(&dev->xmit_lock)) {//鎖已經被獲取
				collision:
					//死鎖:
					//	鎖被占用,但是擁有者為本cpu,將skb丟掉,直接返回-1
					if (dev->xmit_lock_owner == smp_processor_id()) {
						kfree_skb(skb);
						return -1;
					}

					//衝突:
					//	將skb重新入隊
					goto requeue;
			}
			//獲取鎖,將鎖的擁有者設置為本cpu
			dev->xmit_lock_owner = smp_processor_id();
		}
		
		{
			spin_unlock(&dev->queue_lock);
			if (!netif_queue_stopped(dev)) {//設備可以進行傳輸
				int ret;
				//netdev_nit表示ETH_P_ALL類型l3協議的個數
				if (netdev_nit)
					dev_queue_xmit_nit(skb, dev);
				//由驅動程序完成傳輸
				ret = dev->hard_start_xmit(skb, dev);
				if (ret == NETDEV_TX_OK) { 
					if (!nolock) {
						dev->xmit_lock_owner = -1;
						spin_unlock(&dev->xmit_lock);
					}
					spin_lock(&dev->queue_lock);
					return -1;
				}
				if (ret == NETDEV_TX_LOCKED && nolock) {
					spin_lock(&dev->queue_lock);
					goto collision; 
				}
			}

			if (!nolock) { 
				dev->xmit_lock_owner = -1;
				spin_unlock(&dev->xmit_lock);
			} 
			spin_lock(&dev->queue_lock);
			q = dev->qdisc;
		}

requeue:
		//將skb重新入隊
		q->ops->requeue(skb, q);
		//調度設備
		netif_schedule(dev);
		return 1;
	}
	//返回規則隊列中剩餘的skb個數
	return q->q.qlen;
}

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

  上一篇:go COM編程入門第二部分——深入COM服務器
  下一篇:go uva 1398 - Meteor 模擬 99