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 的任何引用,也不得尝试释放它。