Chinaunix首页 | 论坛 | 博客
  • 博客访问: 434464
  • 博文数量: 99
  • 博客积分: 65
  • 博客等级: 民兵
  • 技术积分: 1012
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-20 16:30
个人简介

linux kernel 工程师

文章分类

全部博文(99)

文章存档

2018年(5)

2017年(12)

2016年(27)

2015年(10)

2014年(43)

2012年(2)

我的朋友

分类: LINUX

2014-02-11 11:57:03

1. 网络接收注册软中断

static int __init net_dev_init(void)
{
....
open_softirq(NET_RX_SOFTIRQ, net_rx_action);

}

2. net_rx_action流程

static void net_rx_action(struct softirq_action *h)
{
 struct softnet_data *sd = &__get_cpu_var(softnet_data);
 unsigned long time_limit = jiffies + 2;
 int budget = netdev_budget;  
//netdev_budget。该值默认为300,但是可以在/proc/sys/net/core/netdev_budget中设置, echo xx > netdev_budget
//netdev_budget 用来控制本次sotirq执行的时间
//napi_struct->weight用来控制对一个设备的poll时间,保持多设备之间的平衡

 void *have;

 local_irq_disable();

 while (!list_empty(&sd->poll_list)) { //list_empty可以在关闭irq情况下执行

  struct napi_struct *n;
  int work, weight;

  /* If softirq window is exhuasted then punt.
   * Allow this to run for 2 jiffies since which will allow
   * an average latency of 1.5/HZ.
   */
  if (unlikely(budget <= 0 || time_after(jiffies, time_limit))) //budget用完或超时,结束本次softirq,防止softirq执行超级长的时间
   goto softnet_break;

  local_irq_enable();

  /* Even though interrupts have been re-enabled, this
   * access is safe because interrupts can only add new
   * entries to the tail of this list, and only ->poll()
   * calls can remove this head entry from the list.
   */
  n = list_first_entry(&sd->poll_list, struct napi_struct, poll_list); //list_first_entry可以在中断打开情况下执行

  have = netpoll_poll_lock(n);

  weight = n->weight;

  /* This NAPI_STATE_SCHED test is for avoiding a race
   * with netpoll's poll_napi().  Only the entity which
   * obtains the lock and sees NAPI_STATE_SCHED set will
   * actually make the ->poll() call.  Therefore we avoid
   * accidentally calling ->poll() when NAPI is not scheduled.
   */
  work = 0;
  if (test_bit(NAPI_STATE_SCHED, &n->state)) {
   trace_net_napi_poll(n);
   work = n->poll(n, weight); /* 调用napi的poll函数 */
   trace_napi_poll(n);
  }

  WARN_ON_ONCE(work > weight);  //work 必须满足 <= weight

  budget -= work; //轮询完一个设备,更新budget

  local_irq_disable();

  /* Drivers must not modify the NAPI state if they
   * consume the entire weight.  In such cases this code
   * still "owns" the NAPI instance and therefore can
   * move the instance around on the list at-will.
   */
  //如果一次就把weight消耗光了,说明可能还需要继续轮询这个设备,所以把这个napi放到poll_list的末尾
  if (unlikely(work == weight)) {
   if (unlikely(napi_disable_pending(n))) {
    local_irq_enable();
    napi_complete(n);
    local_irq_disable();
   } else
    list_move_tail(&n->poll_list, &sd->poll_list);
  }

  netpoll_poll_unlock(have);
 }
out:
 net_rps_action_and_irq_enable(sd);

#ifdef CONFIG_NET_DMA
 /*
  * There may not be any more sk_buffs coming right now, so push
  * any pending DMA copies to hardware
  */
 dma_issue_pending_all();
#endif

 return;

softnet_break:
 sd->time_squeeze++;
 __raise_softirq_irqoff(NET_RX_SOFTIRQ); /* 如果budget用完或者超时,跳转到这里,等待下次softirq的执行 */
 goto out;
}

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

上一篇:e1000 网卡NAPI

下一篇:netif_rx

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