Softnet 驱动问题¶
探测指南¶
地址验证¶
您为设备获得的任何硬件层地址都应进行验证。例如,对于以太网,请使用 linux/etherdevice.h 进行检查:is_valid_ether_addr()
关闭/停止指南¶
静止¶
在调用 ndo_stop 例程后,硬件不得接收或传输任何数据。所有正在传输中的数据包都必须中止。如有必要,轮询或等待任何重置命令的完成。
自动关闭¶
如果设备仍处于 UP 状态,则 unregister_netdevice 将调用 ndo_stop 例程。
传输路径指南¶
提前停止队列¶
在任何正常情况下,ndo_start_xmit 方法都不得返回 NETDEV_TX_BUSY。除非您的设备无法提前知道其传输功能何时会变得繁忙,否则这被认为是硬错误。
相反,它必须正确维护队列。例如,对于实现分散-聚集的驱动程序,这意味着
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 队列,而无需完整的锁保护。
我们假设不会有并发的停止尝试,也不会有并发的唤醒尝试。尝试停止应从 xmit 处理程序中发生,而唤醒应从 NAPI 轮询上下文中触发。两者可以并发运行(单生产者,单消费者)。
尝试停止侧预计从 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 的任何引用,也不得尝试释放它。