帧的发送

简介:       上一节我们说了帧的接收,自然有收就有发,并且也很少说关于发送的东西,这里我们就分析下帧的发送.      参考内核2.6.32.60   net/core/dev.c        我们先看看设备无关层的经典发送函数接口 dev_queue_xmit,当然这里要说一下...
      上一节我们说了帧的接收,自然有收就有发,并且也很少说关于发送的东西,这里我们就分析下帧的发送.
     参考内核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详细分析. 到这里已经和帧的接收圆了起来.




     
相关文章
|
9天前
|
编解码 缓存 算法
视频帧里的I帧、P帧、B帧是什么?
I帧、P帧、B帧是视频编码中的基本概念。I帧是帧内编码帧,无需参考其他帧即可解码;P帧是前向预测编码帧,基于前一帧解码;B帧是双向预测编码帧,基于前后帧解码。IDR帧是一种特殊的I帧,用于即时解码刷新,防止错误传播。GOP(Group of Pictures)是一组连续的画面,第一个帧为I帧,gop_size设置越大,画质越好,但解码延迟增加。OpenGOP允许GOP间的帧依赖,而ClosedGOP则不允许。DTS(解码时间戳)和PTS(显示时间戳)分别用于解码和显示时间控制。
|
2月前
|
网络协议 算法 安全
802.11帧结构与WiFi控制帧、管理帧、数据帧
【9月更文挑战第26天】该内容详细介绍了802.11帧结构,包括帧头、帧体和帧尾三部分,并分别阐述了各部分的功能和作用。此外,还介绍了WiFi控制帧、管理帧和数据帧的功能及类型,涵盖了RTS/CTS、ACK、信标帧、关联请求/响应帧、认证帧等内容,解释了它们在网络通信中的具体应用。
183 3
|
6月前
|
网络协议
计算机网络四种帧介绍,广播帧、未知帧、同网帧、异网帧
计算机网络四种帧介绍,广播帧、未知帧、同网帧、异网帧
|
IDE 自动驾驶 安全
CAN FD网络中每秒最多可以发送多少帧报文?
随着总线技术在汽车电子领域越来越广泛和深入的应用,特别是自动驾驶技术的迅速发展,汽车电子对总线宽度和数据传输速率的要求也越来也高,传统CAN(1MBit/s,8Bytes Payload)已难以满足日益增加的需求。
为什么发出去的2833 RTP流不能收号
为什么发出去的2833 RTP流不能收号
为什么发出去的2833 RTP流不能收号
|
机器学习/深度学习 并行计算 算法
MMFlow :帧与帧之间的追光者
光流(Optical Flow),字面理解为“光的流动”,更准确的说法为:时变图像上的二维运动场,是视频数据的重要视觉线索,在动作识别、视频理解、视频分割、目标跟踪以及全景拼接等领域,都有广泛应用。
617 0
MMFlow :帧与帧之间的追光者
|
机器学习/深度学习 缓存
【计算机网络】数据链路层 : 选择重传协议 SR ( 帧分类 | “发送方“ 确认帧、超时事件 | “接受方“ 接收帧机制 | 滑动窗口长度 | 计算示例 )★
【计算机网络】数据链路层 : 选择重传协议 SR ( 帧分类 | “发送方“ 确认帧、超时事件 | “接受方“ 接收帧机制 | 滑动窗口长度 | 计算示例 )★
593 0
|
机器学习/深度学习
【计算机网络】数据链路层 : 后退 N 帧协议 GBN ( 滑动窗口 | 发送窗口长度 | “发送方“ 累计确认、超时机制 | “接收方“ 按序接收、确认帧发送机制 | 计算示例 )★(二)
【计算机网络】数据链路层 : 后退 N 帧协议 GBN ( 滑动窗口 | 发送窗口长度 | “发送方“ 累计确认、超时机制 | “接收方“ 按序接收、确认帧发送机制 | 计算示例 )★(二)
729 0
|
机器学习/深度学习 缓存
【计算机网络】数据链路层 : 后退 N 帧协议 GBN ( 滑动窗口 | 发送窗口长度 | “发送方“ 累计确认、超时机制 | “接收方“ 按序接收、确认帧发送机制 | 计算示例 )★(一)
【计算机网络】数据链路层 : 后退 N 帧协议 GBN ( 滑动窗口 | 发送窗口长度 | “发送方“ 累计确认、超时机制 | “接收方“ 按序接收、确认帧发送机制 | 计算示例 )★(一)
648 0
|
SQL
【计算机网络】数据链路层 : 停止-等待协议 ( 无差错情况 | 有差错情况 | 帧丢失 | 帧出错 | ACK 确认帧丢失 | ACK 确认帧延迟 | 信道利用率公式 | 信道利用率计算 )★(二)
【计算机网络】数据链路层 : 停止-等待协议 ( 无差错情况 | 有差错情况 | 帧丢失 | 帧出错 | ACK 确认帧丢失 | ACK 确认帧延迟 | 信道利用率公式 | 信道利用率计算 )★(二)
412 0