首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 操作系统 > UNIXLINUX >

Linux发送函数dev_queue_xmit分析 -转

2012-12-20 
Linux发送函数dev_queue_xmit分析--转当上层准备好一个包之后,交给下面这个函数处理:?? ?? 从此函数可以看

Linux发送函数dev_queue_xmit分析 --转

当上层准备好一个包之后,交给下面这个函数处理:

??

?? 从此函数可以看出,当驱动使用发送队列的时候会循环从队列中取出包发送
?? 而不使用队列的时候只发送一次,如果没发送成功就直接丢弃

??

static inline int qdisc_restart(struct Qdisc *q)   {       struct netdev_queue *txq;       int ret = NETDEV_TX_BUSY;       struct net_device *dev;       spinlock_t *root_lock;       struct sk_buff *skb;       /* Dequeue packet */      if (unlikely((skb = dequeue_skb(q)) == NULL))           return 0;       root_lock = qdisc_lock(q);       /* And release qdisc */      spin_unlock(root_lock);       dev = qdisc_dev(q);       txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));       HARD_TX_LOCK(dev, txq, smp_processor_id());       if (!netif_tx_queue_stopped(txq) &&           !netif_tx_queue_frozen(txq))           ret = dev_hard_start_xmit(skb, dev, txq);       HARD_TX_UNLOCK(dev, txq);       spin_lock(root_lock);       switch (ret) {       case NETDEV_TX_OK:           /* Driver sent out skb successfully */          ret = qdisc_qlen(q);           break;       case NETDEV_TX_LOCKED:           /* Driver try lock failed */          //有可能其他CPU正占有这个锁,这里处理冲突           //函数就不看了,里面的处理流程简单说下           //分两种情况,如果占有锁的cpu就是当前cpu,那么释放这个包同时打印一条警告           //否则将包重新入队           ret = handle_dev_cpu_collision(skb, txq, q);           break;       default:           /* Driver returned NETDEV_TX_BUSY - requeue skb */          //当发送队列处于停止状态并且队列中有数据待发送时会返回NETDEV_TX_BUSY           //代表发送忙,这种情况下就将包重新入队           if (unlikely (ret != NETDEV_TX_BUSY && net_ratelimit()))               printk(KERN_WARNING "BUG %s code %d qlen %d\n",                      dev->name, ret, q->q.qlen);           ret = dev_requeue_skb(skb, q);           break;       }       if (ret && (netif_tx_queue_stopped(txq) ||               netif_tx_queue_frozen(txq)))           ret = 0;       return ret;   }  

?

? 至此,dev_queue_xmit到驱动层的发送流程就分析完了。

?已经有了dev_queue_xmit函数,为什么还需要软中断来发送呢?
我们可以看到在dev_queue_xmit中将skb进行了一些处理(比如合并成一个包,计算校验和等)
处理完的skb是可以直接发送的了,这时dev_queue_xmit也会先将skb入队(skb一般都是在这个函数中入队的)
并且调用qdisc_run尝试发送,但是有可能发送失败,这时就将skb重新入队,调度软中断,并且自己直接返回。
软中断只是发送队列中的skb以及释放已经发送的skb,它无需再对skb进行线性化或者校验和处理
另外在队列被停止的情况下,dev_queue_xmit仍然可以把包加入队列,但是不能发送
这样在队列被唤醒的时候就需要通过软中断来发送停止期间积压的包
简而言之,dev_queue_xmit是对skb做些最后的处理并且第一次尝试发送,软中断是将前者发送失败或者没发完的包发送出去。
(其实发送软中断还有一个作用,就是释放已经发送的包,因为某些情况下发送是在硬件中断中完成的,
为了提高硬件中断处理效率,内核提供一种方式将释放skb放到软中断中进行,
这时只要调用dev_kfree_skb_irq,它将skb加入softnet_data的completion_queue中,然后开启发送软中断,
net_tx_action会在软中断中将completion_queue中的skb全部释放掉)

?

?本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/peimichael/archive/2009/10/19/4699609.aspx#

热点排行