帧的传输

传输的开启和关闭

出口队列的状态是由net_device->state中的标识__LINK_STATE_XOFF表示。其值可以通过定义在include/linux/device.h中的下列函数操作和检查

netif_state_queue:开启设备的传输,当设备启动时通常就会调用此函数,此外,如果必须重启已停止的设备,也可以再次调用。

netif_stop_queue: 关闭设备的传输,任何企图在设备上传输信息的尝试都会被拒绝。

netif_stop_stopped:返回出口队列的状态

只有设备驱动程序可以开启和关闭设备的传输。

设备停止和启动队列的原因,1,设备可以暂时用尽其内存,使得传输失败。当设备上有足够内存时,程序会调用netif_start_queue。

net_tx_action:

1,当设备的传输功能通过netif_wake_queue开启时,在这种情况下,此函数要确保当所有必需条件都吻合时,等待被传送的帧实际上都被传送出去。

2,当传输已完成而且设备驱动程序通过dev_kfree_skb_irq通知相关联的缓冲区可释放时,在这种情况下,此函数要收回那些已成功传输的缓冲区的sk_buff结构。第二项任务的原因如下,当来自设备驱动程序的程序在中断环境下运行时,就必须尽快执行。释放一个缓冲区会耗时间,所以会受到拖延,而要求net_tx_action软中断予以负责。设备驱动程序不使用dev_kfree_skb,而是使用dev_kfree_skb_irq。dev_kfree_skb_irq只会把要被释放的缓冲区的指针添加到与CPU相关联的softnet_data结构的completion_queue列表中,然后让net_tx_action稍后去做实际工作。

   1:  static void net_tx_action(struct softirq_action *h)
   2:  {
   3:      struct softnet_data *sd = &__get_cpu_var(softnet_data);
   4:   
   5:      if (sd->completion_queue) {
   6:          struct sk_buff *clist;
   7:   
   8:          local_irq_disable();
   9:          clist = sd->completion_queue;
  10:          sd->completion_queue = NULL;
  11:          local_irq_enable();
  12:   
  13:          while (clist) {
  14:              struct sk_buff *skb = clist;
  15:              clist = clist->next;
  16:   
  17:              WARN_ON(atomic_read(&skb->users));
  18:              trace_kfree_skb(skb, net_tx_action);
  19:              __kfree_skb(skb);
  20:          }
  21:      }
  22:   
  23:      if (sd->output_queue) {
  24:          struct Qdisc *head;
  25:   
  26:          local_irq_disable();
  27:          head = sd->output_queue;
  28:          sd->output_queue = NULL;
  29:          sd->output_queue_tailp = &sd->output_queue;
  30:          local_irq_enable();
  31:   
  32:          while (head) {
  33:              struct Qdisc *q = head;
  34:              spinlock_t *root_lock;
  35:   
  36:              head = head->next_sched;
  37:   
  38:              root_lock = qdisc_lock(q);
  39:              if (spin_trylock(root_lock)) {
  40:                  smp_mb__before_clear_bit();
  41:                  clear_bit(__QDISC_STATE_SCHED,
  42:                        &q->state);
  43:                  qdisc_run(q);
  44:                  spin_unlock(root_lock);
  45:              } else {
  46:                  if (!test_bit(__QDISC_STATE_DEACTIVATED,
  47:                            &q->state)) {
  48:                      __netif_reschedule(q);
  49:                  } else {
  50:                      smp_mb__before_clear_bit();
  51:                      clear_bit(__QDISC_STATE_SCHED,
  52:                            &q->state);
  53:                  }
  54:              }
  55:          }
  56:      }
  57:  }

函数的前一半任务就是完成对skb的内存释放。关闭中断后,在局部变量中,取下待释放的内存指针,然后开中断,然后遍历,释放内存。

你可能感兴趣的:(帧的传输)