Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1190774
  • 博文数量: 56
  • 博客积分: 400
  • 博客等级: 一等列兵
  • 技术积分: 2800
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-30 13:08
个人简介

一个人的差异在于业余时间

文章分类

全部博文(56)

文章存档

2023年(1)

2019年(1)

2018年(1)

2017年(1)

2016年(2)

2015年(20)

2014年(10)

2013年(7)

2012年(12)

2011年(1)

分类: LINUX

2014-05-15 19:22:55

      上一节我们说了帧的接收,自然有收就有发,并且也很少说关于发送的东西,这里我们就分析下帧的发送.
     参考内核2.6.32.60   net/core/dev.c  
     我们先看看设备无关层的经典发送函数接口 dev_queue_xmit,当然这里要说一下,上层是如何调用到这里的,当然数据发送到ip层的时候,会调用到邻居子系统模块会把这个接口给联系起来,因为要给数据包封装帧头.查询arp表,找到ip和mac的对应关系当然还有接口的.

点击(此处)折叠或打开

  1. /* This function can be used in contexts, where only old dev_queue_xmit
  2.    worked, f.e. if you want to override normal output path (eql, shaper),
  3.    but resolution is not made yet.
  4.  */

  5. int neigh_compat_output(struct sk_buff *skb)
  6. {
  7.     struct net_device *dev = skb->dev;

  8.     __skb_pull(skb, skb_network_offset(skb));

  9.     if (dev_hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL,
  10.              skb->len) < 0 &&
  11.      dev->header_ops->rebuild(skb))
  12.         return 0;

  13.     return dev_queue_xmit(skb);
  14. }
这里不多说上层的流程.

点击(此处)折叠或打开

  1. /**
  2.  *    dev_queue_xmit - transmit a buffer
  3.  *    @skb: buffer to transmit
  4.  *
  5.  *    Queue a buffer for transmission to a network device. The caller must
  6.  *    have set the device and priority and built the buffer before calling
  7.  *    this function. The function can be called from an interrupt.
  8.  *
  9.  *    A negative errno code is returned on a failure. A success does not
  10.  *    guarantee the frame will be transmitted as it may be dropped due
  11.  *    to congestion or traffic shaping.
  12.  *
  13.  * -----------------------------------------------------------------------------------
  14.  * I notice this method can also return errors from the queue disciplines,
  15.  * including NET_XMIT_DROP, which is a positive value. So, errors can also
  16.  * be positive.
  17.  *
  18.  * Regardless of the return value, the skb is consumed, so it is currently
  19.  * difficult to retry a send to this method. (You can bump the ref count
  20.  * before sending to hold a reference for retry if you are careful.)
  21.  *
  22.  * When calling this method, interrupts MUST be enabled. This is because
  23.  * the BH enable code must have IRQs enabled so that it will not deadlock.
  24.  * --BLG
  25.  */
  26. int dev_queue_xmit(struct sk_buff *skb)
  27. {
  28.     struct net_device *dev = skb->dev;
  29.     struct netdev_queue *txq;
  30.     struct Qdisc *q;
  31.     int rc = -ENOMEM;

  32.     /* GSO will handle the following emulations directly. */
  33.     if (netif_needs_gso(dev, skb))     //帧的聚合/分散  用来提高网络性能 可以参考tso,如果有了支持TSO的网卡,CPU可以直接将要发送的大数据发送到网卡上                                       //,由网卡硬件去负责分片和计算校验和;同时也需要支持硬件校验和 
  34.         goto gso;

  35.     if (skb_has_frags(skb) &&              //这里判断帧是否有分片,如果有把分片的部分,组合到一起发送.
  36.      !(dev->features & NETIF_F_FRAGLIST) &&
  37.      __skb_linearize(skb))
  38.         goto out_kfree_skb;

  39.     /* Fragmented skb is linearized if device does not support SG,
  40.      * or if at least one of fragments is in highmem and device
  41.      * does not support DMA from it.
  42.      */
  43.     if (skb_shinfo(skb)->nr_frags &&
  44.      (!(dev->features & NETIF_F_SG) || illegal_highdma(dev, skb)) &&
  45.      __skb_linearize(skb))
  46.         goto out_kfree_skb;

  47.     /* If packet is not checksummed and device does not support
  48.      * checksumming for this protocol, complete checksumming here.
  49.      */
  50.     if (skb->ip_summed == CHECKSUM_PARTIAL) {                 // 软件 校验L4 校验和,然后准备发送帧.
  51.         skb_set_transport_header(skb, skb->csum_start -
  52.                      skb_headroom(skb));
  53.         if (!dev_can_checksum(dev, skb) && skb_checksum_help(skb))
  54.             goto out_kfree_skb;
  55.     }

  56. gso:
  57.     /* Disable soft irqs for various locks below. Also
  58.      * stops preemption for RCU.
  59.      */
  60.     rcu_read_lock_bh();

  61.     txq = dev_pick_tx(dev, skb);
  62.     q = rcu_dereference(txq->qdisc);

  63. #ifdef CONFIG_NET_CLS_ACT                // 这里默认开启了这个选项,即qos,流量控制 
  64.     skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_EGRESS);
  65. #endif
  66.     if (q->enqueue) {
  67.         rc = __dev_xmit_skb(skb, q, dev, txq);
  68.         goto out;
  69.     }

  70.     /* The device has no queue. Common case for software devices:
  71.      loopback, all the sorts of tunnels...

  72.      Really, it is unlikely that netif_tx_lock protection is necessary
  73.      here. (f.e. loopback and IP tunnels are clean ignoring statistics
  74.      counters.)
  75.      However, it is possible, that they rely on protection
  76.      made by us here.

  77.      Check this and shot the lock. It is not prone from deadlocks.
  78.      Either shot noqueue qdisc, it is even simpler 8)
  79.      */
  80.     if (dev->flags & IFF_UP) {
  81.         int cpu = smp_processor_id(); /* ok because BHs are off */

  82.         if (txq->xmit_lock_owner != cpu) {

  83.             HARD_TX_LOCK(dev, txq, cpu);

  84.             if (!netif_tx_queue_stopped(txq)) {
  85.                 rc = NET_XMIT_SUCCESS;
  86.                 if (!dev_hard_start_xmit(skb, dev, txq)) {
  87.                     HARD_TX_UNLOCK(dev, txq);
  88.                     goto out;
  89.                 }
  90.             }
  91.             HARD_TX_UNLOCK(dev, txq);
  92.             if (net_ratelimit())
  93.                 printk(KERN_CRIT "Virtual device %s asks to "
  94.                  "queue packet!\n", dev->name);
  95.         } else {
  96.             /* Recursion is It is possible,
  97.              * unfortunately */
  98.             if (net_ratelimit())
  99.                 printk(KERN_CRIT "Dead loop on virtual device "
  100.                  "%s, fix it urgently!\n", dev->name);
  101.         }
  102.     }

  103.     rc = -ENETDOWN;
  104.     rcu_read_unlock_bh();

  105. out_kfree_skb:
  106.     kfree_skb(skb);
  107.     return rc;
  108. out:
  109.     rcu_read_unlock_bh();
  110.     return rc;
  111. }
我们这里说一下q->enqueue ,它到底为真还是空呢?

点击(此处)折叠或打开

  1. txq = dev_pick_tx(dev, skb);
  2.     q = rcu_dereference(txq->qdisc);

点击(此处)折叠或打开

  1. static struct netdev_queue *dev_pick_tx(struct net_device *dev,
  2.                     struct sk_buff *skb)
  3. {
  4.     const struct net_device_ops *ops = dev->netdev_ops;
  5.     u16 queue_index = 0;

  6.     if (ops->ndo_select_queue)
  7.         queue_index = ops->ndo_select_queue(dev, skb);
  8.     else if (dev->real_num_tx_queues > 1)
  9.         queue_index = skb_tx_hash(dev, skb);

  10.     skb_set_queue_mapping(skb, queue_index);
  11.     return netdev_get_tx_queue(dev, queue_index);
  12. }
这里很明显是获取tx qdisc. 而ops我们如果看过网卡驱动,就知道默认很少有人去初始化.ndo_select_queue,
而dev->real_num_tx_queues在前面文章中我们知道默认初始化为1. 所以这个函数的返回值是:
&dev->_tx[index]; // 而index明显是0 . 也是说是_tx数组的第一个元素.
我们回想到设备注册函数中的dev_init_scheduler就明白了.默认初始化qdisc是noop_qdisc
在sch_generic.c中

点击(此处)折叠或打开

  1. struct Qdisc noop_qdisc = {
  2.     .enqueue    =    noop_enqueue,
  3.     .dequeue    =    noop_dequeue,
  4.     .flags        =    TCQ_F_BUILTIN,
  5.     .ops        =    &noop_qdisc_ops,
  6.     .list        =    LIST_HEAD_INIT(noop_qdisc.list),
  7.     .q.lock        =    __SPIN_LOCK_UNLOCKED(noop_qdisc.q.lock),
  8.     .dev_queue    =    &noop_netdev_queue,
  9. }
当然后来,在dev_open的时候,里面有

点击(此处)折叠或打开

  1. /*
  2.          *    Wakeup transmit queue engine
  3.          */
  4.         dev_activate(dev);
又重新初始化了.

点击(此处)折叠或打开

  1. void dev_activate(struct net_device *dev)
  2. {
  3.     int need_watchdog;

  4.     /* No queueing discipline is attached to device;
  5.      create default one i.e. pfifo_fast for devices,
  6.      which need queueing and noqueue_qdisc for
  7.      virtual interfaces
  8.      */

  9.     if (dev->qdisc == &noop_qdisc)
  10.         attach_default_qdiscs(dev);

  11.     if (!netif_carrier_ok(dev))
  12.         /* Delay activation until next carrier-on event */
  13.         return;

  14.     need_watchdog = 0;
  15.     netdev_for_each_tx_queue(dev, transition_one_qdisc, &need_watchdog);
  16.     transition_one_qdisc(dev, &dev->rx_queue, NULL);

  17.     if (need_watchdog) {
  18.         dev->trans_start = jiffies;
  19.         dev_watchdog_up(dev);
  20.     }
  21. }
我们看看 attach_default_qdiscs(dev);

点击(此处)折叠或打开

  1. static void attach_default_qdiscs(struct net_device *dev)
  2. {
  3.     struct netdev_queue *txq;
  4.     struct Qdisc *qdisc;

  5.     txq = netdev_get_tx_queue(dev, 0);

  6.     if (!netif_is_multiqueue(dev) || dev->tx_queue_len == 0) {
  7.         netdev_for_each_tx_queue(dev, attach_one_default_qdisc, NULL);
  8.         dev->qdisc = txq->qdisc_sleeping;
  9.         atomic_inc(&dev->qdisc->refcnt);
  10.     } else {
  11.         qdisc = qdisc_create_dflt(dev, txq, &mq_qdisc_ops, TC_H_ROOT);
  12.         if (qdisc) {
  13.             qdisc->ops->attach(qdisc);
  14.             dev->qdisc = qdisc;
  15.         }
  16.     }
  17. }
这里有初始化为了mq_qdisc_ops.而它的enqueue函数是:
pfifo_enqueue://sch_fifo.c 

点击(此处)折叠或打开

  1. static int pfifo_enqueue(struct sk_buff *skb, struct Qdisc* sch)
  2. {
  3.     struct fifo_sched_data *q = qdisc_priv(sch);

  4.     if (likely(skb_queue_len(&sch->q) < q->limit))
  5.         return qdisc_enqueue_tail(skb, sch);

  6.     return qdisc_reshape_fail(skb, sch);
  7. }
所以会进入:

点击(此处)折叠或打开

  1. static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
  2.                  struct net_device *dev,
  3.                  struct netdev_queue *txq)
  4. {
  5.     spinlock_t *root_lock = qdisc_lock(q);
  6.     int rc;

  7.     spin_lock(root_lock);
  8.     if (unlikely(test_bit(__QDISC_STATE_DEACTIVATED, &q->state))) {  // qdisc 没有激活,当然不可能了,前面dev_open的时候~。~
  9.         kfree_skb(skb);
  10.         rc = NET_XMIT_DROP;
  11.     } else if ((q->flags & TCQ_F_CAN_BYPASS) && !qdisc_qlen(q) &&     //  预留的一些操作,暂时我也没看懂,但是从qdis_qlen可以知道qlen为空才会进入....
  12.          !test_and_set_bit(__QDISC_STATE_RUNNING, &q->state)) {
  13.         /*
  14.          * This is a work-conserving queue; there are no old skbs
  15.          * waiting to be sent out; and the qdisc is not running -
  16.          * xmit the skb directly.
  17.          */
  18.         __qdisc_update_bstats(q, skb->len);
  19.         if (sch_direct_xmit(skb, q, dev, txq, root_lock))
  20.             __qdisc_run(q);
  21.         else
  22.             clear_bit(__QDISC_STATE_RUNNING, &q->state);

  23.         rc = NET_XMIT_SUCCESS;
  24.     } else { //正常进入这里.
  25.         rc = qdisc_enqueue_root(skb, q);
  26.         qdisc_run(q);
  27.     }
  28.     spin_unlock(root_lock);

  29.     return rc;
  30. }
qdisc_enqueue_root 会调用enqueue加入队列,然后调用qdisc_run .它设置队列状态为running然后调用:

点击(此处)折叠或打开

  1. void __qdisc_run(struct Qdisc *q)
  2. {
  3.     unsigned long start_time = jiffies;

  4.     while (qdisc_restart(q)) {
  5.         /*
  6.          * Postpone processing if
  7.          * 1. another process needs the CPU;
  8.          * 2. we've been doing it for too long.
  9.          */
  10.         if (need_resched() || jiffies != start_time) {
  11.             __netif_schedule(q);
  12.             break;
  13.         }
  14.     }

  15.     clear_bit(__QDISC_STATE_RUNNING, &q->state);
  16. }
这里先说下while内的代码. 看注释我们明白,需要延迟处理呗. 然后调用__netif_schedule。

点击(此处)折叠或打开

  1. void __netif_schedule(struct Qdisc *q)
  2. {
  3.     if (!test_and_set_bit(__QDISC_STATE_SCHED, &q->state))
  4.         __netif_reschedule(q);
  5. }

点击(此处)折叠或打开

  1. static inline void __netif_reschedule(struct Qdisc *q)
  2. {
  3.     struct softnet_data *sd;
  4.     unsigned long flags;

  5.     local_irq_save(flags);
  6.     sd = &__get_cpu_var(softnet_data);
  7.     q->next_sched = sd->output_queue;
  8.     sd->output_queue = q;
  9.     raise_softirq_irqoff(NET_TX_SOFTIRQ);
  10.     local_irq_restore(flags);
  11. }
看到上面的代码我们是否明白点什么,对,就是软中断发送中断的调用处. 当然关于rx软中断前面napi机制里已经说的很清楚了.

点击(此处)折叠或打开

  1. static void net_tx_action(struct softirq_action *h)
  2. {
  3.     struct softnet_data *sd = &__get_cpu_var(softnet_data);

  4.     if (sd->completion_queue) {   //已经发送完的报文,但是buff还没释放
  5.         struct sk_buff *clist;

  6.         local_irq_disable();
  7.         clist = sd->completion_queue;
  8.         sd->completion_queue = NULL;
  9.         local_irq_enable();

  10.         while (clist) {
  11.             struct sk_buff *skb = clist;
  12.             clist = clist->next;

  13.             WARN_ON(atomic_read(&skb->users));
  14.             __kfree_skb(skb);
  15.         }
  16.     }

  17.     if (sd->output_queue) {
  18.         struct Qdisc *head;

  19.         local_irq_disable();
  20.         head = sd->output_queue;
  21.         sd->output_queue = NULL;
  22.         local_irq_enable();

  23.         while (head) {
  24.             struct Qdisc *q = head;
  25.             spinlock_t *root_lock;

  26.             head = head->next_sched;

  27.             root_lock = qdisc_lock(q);
  28.             if (spin_trylock(root_lock)) {
  29.                 smp_mb__before_clear_bit();
  30.                 clear_bit(__QDISC_STATE_SCHED,
  31.                      &q->state);
  32.                 qdisc_run(q);
  33.                 spin_unlock(root_lock);
  34.             } else {
  35.                 if (!test_bit(__QDISC_STATE_DEACTIVATED,
  36.                      &q->state)) {
  37.                     __netif_reschedule(q);
  38.                 } else {
  39.                     smp_mb__before_clear_bit();
  40.                     clear_bit(__QDISC_STATE_SCHED,
  41.                          &q->state);
  42.                 }
  43.             }
  44.         }
  45.     }
  46. }
在处理延迟的output_queue时,最后又调用到qdisc_run. 本质都会调用qdisc_restart. 直到数据发送完.

点击(此处)折叠或打开

  1. /*
  2.  * NOTE: Called under qdisc_lock(q) with locally disabled BH.
  3.  *
  4.  * __QDISC_STATE_RUNNING guarantees only one CPU can process
  5.  * this qdisc at a time. qdisc_lock(q) serializes queue accesses for
  6.  * this queue.
  7.  *
  8.  * netif_tx_lock serializes accesses to device driver.
  9.  *
  10.  * qdisc_lock(q) and netif_tx_lock are mutually exclusive,
  11.  * if one is grabbed, another must be free.
  12.  *
  13.  * Note, that this procedure can be called by a watchdog timer
  14.  *
  15.  * Returns to the caller:
  16.  *                0 - queue is empty or throttled.
  17.  *                >0 - queue is not empty.
  18.  *
  19.  */
  20. static inline int qdisc_restart(struct Qdisc *q)
  21. {
  22.     struct netdev_queue *txq;
  23.     struct net_device *dev;
  24.     spinlock_t *root_lock;
  25.     struct sk_buff *skb;

  26.     /* Dequeue packet */
  27.     skb = dequeue_skb(q);
  28.     if (unlikely(!skb))
  29.         return 0;

  30.     root_lock = qdisc_lock(q);
  31.     dev = qdisc_dev(q);
  32.     txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));

  33.     return sch_direct_xmit(skb, q, dev, txq, root_lock);
  34. }
这里我们看到了dequeue函数的调用,它就是qdisc生效的地方,具体不多说.然后是直接sch_direct_xmit发送

点击(此处)折叠或打开

  1. /*
  2.  * Transmit one skb, and handle the return status as required. Holding the
  3.  * __QDISC_STATE_RUNNING bit guarantees that only one CPU can execute this
  4.  * function.
  5.  *
  6.  * Returns to the caller:
  7.  *                0 - queue is empty or throttled.
  8.  *                >0 - queue is not empty.
  9.  */
  10. int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q,
  11.          struct net_device *dev, struct netdev_queue *txq,
  12.          spinlock_t *root_lock)
  13. {
  14.     int ret = NETDEV_TX_BUSY;

  15.     /* And release qdisc */
  16.     spin_unlock(root_lock);

  17.     HARD_TX_LOCK(dev, txq, smp_processor_id());
  18.     if (!netif_tx_queue_stopped(txq) &&
  19.      !netif_tx_queue_frozen(txq))
  20.         ret = dev_hard_start_xmit(skb, dev, txq);
  21.     HARD_TX_UNLOCK(dev, txq);

  22.     spin_lock(root_lock);

  23.     switch (ret) {
  24.     case NETDEV_TX_OK:
  25.         /* Driver sent out skb successfully */
  26.         ret = qdisc_qlen(q);
  27.         break;

  28.     case NETDEV_TX_LOCKED:
  29.         /* Driver try lock failed */
  30.         ret = handle_dev_cpu_collision(skb, txq, q);
  31.         break;

  32.     default:
  33.         /* Driver returned NETDEV_TX_BUSY - requeue skb */
  34.         if (unlikely (ret != NETDEV_TX_BUSY && net_ratelimit()))
  35.             printk(KERN_WARNING "BUG %s code %d qlen %d\n",
  36.              dev->name, ret, q->q.qlen);

  37.         ret = dev_requeue_skb(skb, q);
  38.         break;
  39.     }

  40.     if (ret && (netif_tx_queue_stopped(txq) ||
  41.          netif_tx_queue_frozen(txq)))
  42.         ret = 0;

  43.     return ret;
  44. }
这个函数有几个工作:
1.dev_hard_start_xmit  直接调用网卡驱动发送出去
2.根据第一步的返回值,继续处理,如果发送失败,又分处理
3.如果是locked ,那么就调用冲突处理
4.其他重新入队列继续发送.
基本又重新循环了,直到数据报文发送成功或者丢弃.

点击(此处)折叠或打开

  1. int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
  2.             struct netdev_queue *txq)
  3. {
  4.     const struct net_device_ops *ops = dev->netdev_ops;
  5.     int rc;

  6.     if (likely(!skb->next)) {
  7.         if (!list_empty(&ptype_all))
  8.             dev_queue_xmit_nit(skb, dev);    //  嗅探器

  9.         if (netif_needs_gso(dev, skb)) {
  10.             if (unlikely(dev_gso_segment(skb)))
  11.                 goto out_kfree_skb;
  12.             if (skb->next)
  13.                 goto gso;
  14.         }

  15.         /*
  16.          * If device doesnt need skb->dst, release it right now while
  17.          * its hot in this cpu cache
  18.          */
  19.         if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
  20.             skb_dst_drop(skb);

  21.         rc = ops->ndo_start_xmit(skb, dev);      //调用网卡驱动发送
  22.         if (rc == NETDEV_TX_OK)
  23.             txq_trans_update(txq);
  24.         /*
  25.          * TODO: if skb_orphan() was called by
  26.          * dev->hard_start_xmit() (for example, the unmodified
  27.          * igb driver does that; bnx2 doesn't), then
  28.          * skb_tx_software_timestamp() will be unable to send
  29.          * back the time stamp.
  30.          *
  31.          * How can this be prevented? Always create another
  32.          * reference to the socket before calling
  33.          * dev->hard_start_xmit()? Prevent that skb_orphan()
  34.          * does anything in dev->hard_start_xmit() by clearing
  35.          * the skb destructor before the call and restoring it
  36.          * afterwards, then doing the skb_orphan() ourselves?
  37.          */
  38.         return rc;
  39.     }

  40. gso:
  41.     do {
  42.         struct sk_buff *nskb = skb->next;

  43.         skb->next = nskb->next;
  44.         nskb->next = NULL;

  45.         /*
  46.          * If device doesnt need nskb->dst, release it right now while
  47.          * its hot in this cpu cache
  48.          */
  49.         if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
  50.             skb_dst_drop(nskb);

  51.         rc = ops->ndo_start_xmit(nskb, dev);     //调用网卡驱动发送
  52.         if (unlikely(rc != NETDEV_TX_OK)) {
  53.             nskb->next = skb->next;
  54.             skb->next = nskb;
  55.             return rc;
  56.         }
  57.         txq_trans_update(txq);
  58.         if (unlikely(netif_tx_queue_stopped(txq) && skb->next))
  59.             return NETDEV_TX_BUSY;
  60.     } while (skb->next);

  61.     skb->destructor = DEV_GSO_CB(skb)->destructor;

  62. out_kfree_skb:
  63.     kfree_skb(skb);
  64.     return NETDEV_TX_OK;
  65. }
这个函数主要功能是如果设置了嗅探器,则dev_queue_xmit_nit复制一份,这个在前面接收的时候也说到过,它这里查询ptype_all链表,注册的类型是eth_all

点击(此处)折叠或打开

  1. /*
  2.  *    Support routine. Sends outgoing frames to any network
  3.  *    taps currently in use.
  4.  */

  5. static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
  6. {
  7.     struct packet_type *ptype;

  8. #ifdef CONFIG_NET_CLS_ACT
  9.     if (!(skb->tstamp.tv64 && (G_TC_FROM(skb->tc_verd) & AT_INGRESS)))
  10.         net_timestamp(skb);
  11. #else
  12.     net_timestamp(skb);
  13. #endif

  14.     rcu_read_lock();
  15.     list_for_each_entry_rcu(ptype, &ptype_all, list) {
  16.         /* Never send packets back to the socket
  17.          * they originated from - MvS (miquels@drinkel.ow.org)
  18.          */
  19.         if ((ptype->dev == dev || !ptype->dev) &&
  20.          (ptype->af_packet_priv == NULL ||
  21.          (struct sock *)ptype->af_packet_priv != skb->sk)) {
  22.             struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
  23.             if (!skb2)
  24.                 break;

  25.             /* skb->nh should be correctly
  26.              set by sender, so that the second statement is
  27.              just protection against buggy protocols.
  28.              */
  29.             skb_reset_mac_header(skb2);

  30.             if (skb_network_header(skb2) < skb2->data ||
  31.              skb2->network_header > skb2->tail) {
  32.                 if (net_ratelimit())
  33.                     printk(KERN_CRIT "protocol %04x is "
  34.                      "buggy, dev %s\n",
  35.                      skb2->protocol, dev->name);
  36.                 skb_reset_network_header(skb2);
  37.             }

  38.             skb2->transport_header = skb2->network_header;
  39.             skb2->pkt_type = PACKET_OUTGOING;
  40.             ptype->func(skb2, skb->dev, ptype, skb->dev);
  41.         }
  42.     }
  43.     rcu_read_unlock();
  44. }
说了这么多,我们看看没有队列的设备,

点击(此处)折叠或打开

  1. /* The device has no queue. Common case for software devices:
  2.      loopback, all the sorts of tunnels...

  3.      Really, it is unlikely that netif_tx_lock protection is necessary
  4.      here. (f.e. loopback and IP tunnels are clean ignoring statistics
  5.      counters.)
  6.      However, it is possible, that they rely on protection
  7.      made by us here.

  8.      Check this and shot the lock. It is not prone from deadlocks.
  9.      Either shot noqueue qdisc, it is even simpler 8)
  10.      */
  11.     if (dev->flags & IFF_UP) {
当然设备必须是开启的,up状态,典型的例子就是回环设备. 它没有队列的处理,而是直接把包发送出去,如果发送失败也不会重新发送,而是直接丢弃了.

这里我们只是大致说了下帧从ip层到驱动层的发送,没有涉及ip以上和网卡驱动的具体函数. 网卡驱动可以具体看驱动实例即可.关于流量控制这里只是简单说了一下调用流程,
具体分析还需要结合tc命令以及iptables详细分析. 到这里已经和帧的接收圆了起来.




     
阅读(4568) | 评论(0) | 转发(0) |
0

上一篇:帧的接收

下一篇:Linux实现的IEEE 802.1Q VLAN

给主人留下些什么吧!~~