Softnet 驅動程式問題¶
探測指南¶
地址驗證¶
應驗證從裝置獲得的任何硬體層地址。 例如,對於乙太網,請使用 linux/etherdevice.h 檢查:is_valid_ether_addr()
關閉/停止指南¶
靜止¶
呼叫 ndo_stop 例程後,硬體不得接收或傳送任何資料。 所有正在傳輸的資料包都必須中止。 如果需要,輪詢或等待任何重置命令完成。
自動關閉¶
如果裝置仍處於 UP 狀態,unregister_netdevice 將呼叫 ndo_stop 例程。
傳輸路徑指南¶
提前停止佇列¶
在任何正常情況下,ndo_start_xmit 方法都不得返回 NETDEV_TX_BUSY。 除非您的裝置無法提前知道其傳輸功能何時會變忙,否則這被認為是硬錯誤。
相反,它必須正確維護佇列。 例如,對於實現 scatter-gather 的驅動程式,這意味著
static u32 drv_tx_avail(struct drv_ring *dr)
{
u32 used = READ_ONCE(dr->prod) - READ_ONCE(dr->cons);
return dr->tx_ring_size - (used & bp->tx_ring_mask);
}
static netdev_tx_t drv_hard_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct drv *dp = netdev_priv(dev);
struct netdev_queue *txq;
struct drv_ring *dr;
int idx;
idx = skb_get_queue_mapping(skb);
dr = dp->tx_rings[idx];
txq = netdev_get_tx_queue(dev, idx);
//...
/* This should be a very rare race - log it. */
if (drv_tx_avail(dr) <= skb_shinfo(skb)->nr_frags + 1) {
netif_stop_queue(dev);
netdev_warn(dev, "Tx Ring full when queue awake!\n");
return NETDEV_TX_BUSY;
}
//... queue packet to card ...
netdev_tx_sent_queue(txq, skb->len);
//... update tx producer index using WRITE_ONCE() ...
if (!netif_txq_maybe_stop(txq, drv_tx_avail(dr),
MAX_SKB_FRAGS + 1, 2 * MAX_SKB_FRAGS))
dr->stats.stopped++;
//...
return NETDEV_TX_OK;
}
然後在您的 TX 回收事件處理結束時
//... update tx consumer index using WRITE_ONCE() ...
netif_txq_completed_wake(txq, cmpl_pkts, cmpl_bytes,
drv_tx_avail(dr), 2 * MAX_SKB_FRAGS);
無鎖佇列停止/喚醒輔助宏¶
netif_txq_maybe_stop() 和 __netif_txq_completed_wake() 宏旨在安全地實現停止和喚醒 netdev 佇列,而無需完全鎖定保護。
我們假設不會有併發的停止嘗試,也不會有併發的喚醒嘗試。 try-stop 應該從 xmit 處理程式發生,而喚醒應該從 NAPI 輪詢上下文觸發。 這兩者可以併發執行(單生產者,單消費者)。
try-stop 側預計從 xmit 處理程式執行,因此它不會重新安排 Tx(netif_tx_start_queue() 代替 netif_tx_wake_queue())。 在 xmit 處理程式之外使用 stop 宏可能會導致啟用 xmit 佇列但未執行。 喚醒側沒有類似的環境限制。
這些宏保證如果有可用空間,環將不會保持停止狀態,但它們不能阻止環已滿時的錯誤喚醒! 驅動程式應在 xmit 處理程式啟動時檢查環是否已滿。
在呼叫宏之前,必須更新所有描述符環索引(和其他相關的共享狀態)。
無獨佔所有權¶
ndo_start_xmit 方法不得修改克隆 SKB 的共享部分。
及時完成¶
不要忘記,一旦您從 ndo_start_xmit 方法返回 NETDEV_TX_OK,您的驅動程式就有責任在有限的時間內釋放 SKB。
例如,這意味著如果未傳送新的 TX 資料包,您的 TX 緩解方案不允許 TX 資料包“掛起”在 TX 環中,永遠無法回收。 如果沒有釋放傳送緩衝區空間,此錯誤可能會導致套接字死鎖。
如果您從 ndo_start_xmit 方法返回 NETDEV_TX_BUSY,則不得保留對該 SKB 的任何引用,也不得嘗試釋放它。