当前位置:嗨网首页>书籍在线阅读

10-数据发送流程

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

16.5 数据发送流程

从16.1节网络设备驱动程序的结构分析可知,Linux网络子系统在发送数据包时,会调用驱动程序提供的hard_start_transmit()函数,该函数用于启动数据包的发送。在设备初始化的时候,这个函数指针需被初始化指向设备的xxx_tx()函数。

网络设备驱动完成数据包发送的流程如下。

(1)网络设备驱动程序从上层协议传递过来的sk_buff参数获得数据包的有效数据和长度,将有效数据放入临时缓冲区。

(2)对于以太网,如果有效数据的长度小于以太网冲突检测所要求数据帧的最小长度ETH_ZLEN,则给临时缓冲区的末尾填充0。

(3)设置硬件的寄存器,驱使网络设备进行数据发送操作。

完成以上3个步骤的网络设备驱动程序的数据包发送函数的模板如代码清单16.7所示。

代码清单16.7 网络设备驱动程序的数据包发送函数模板

1 int xxx_tx(struct sk_buff skb, struct net_device dev)

2 {

3 int len;

4 char *data, shortpkt[ETH_ZLEN];

5 if (xxx_send_available(...)) { / 发送队列未满,可以发送 /

6 / 获得有效数据指针和长度 /

7 data = skb->data;

8 len = skb->len;

9 if (len < ETH_ZLEN) {

10 / 如果帧长小于以太网帧最小长度,补0 /

11 memset(shortpkt, 0, ETH_ZLEN);

12 memcpy(shortpkt, skb->data, skb->len);

13 len = ETH_ZLEN;

14 data = shortpkt;

15 }

16

17 dev->trans_start = jiffies; / 记录发送时间戳 /

18

19 / 设置硬件寄存器让硬件把数据包发送出去 /

20 xxx_hw_tx(data, len, dev);

21 ...

22 } else {

23 netif_stop_queue(dev);

24 ...

25 }

26 }

这里特别要强调第23行对netif_stop_queue()的调用,当发送队列为满或因其他原因来不及发送当前上层传下来的包,则调用此函数阻止上层继续向网络设备驱动传递数据包。当忙于发送的数据包被发送完成后,TX结束的中断处理中,应该调用netif_wake_queue()唤醒被阻塞的上层,以启动它继续向网络设备驱动传送数据包。

当数据传输超时时,意味着当前的发送操作失败或硬件已陷入未知状态,此时,数据包发送超时处理函数xxx_tx_timeout()将被调用。这个函数也需要调用Linux内核提供的netifwake queue()函数重新启动设备发送队列,如代码清单16.8所示。

代码清单16.8 网络设备驱动程序的数据包发送超时函数模板

1 void xxx_tx_timeout(struct net_device *dev)

2 {

3 ...

4 netif_wake_queue(dev); / 重新启动设备发送队列 /

5 }

从前文可知,netif_wake_queue()和netif_stop_queue()是数据发送流程中要调用的两个非常重要的函数,分别用于唤醒和阻止上层向下传送数据包,它们的原型定义于include/linux/netdevice.h,如下:

static inline void netif_wake_queue(struct net_device *dev);

static inline void netif_stop_queue(struct net_device *dev);