Kernel数据包处理基础

来源:互联网 发布:联通免费流量软件 编辑:程序博客网 时间:2024/06/11 05:01

(内容主要来自“深入理解Linux网络内幕”一书)


数据包接收可以分为两部分:

1. 驱动

  * 驱动将frame拷贝到sk_buff,然后放入input queue。这里是中断context,可以抢占第二部分(kernel部分)。

  * 通过调度NET_RX_SOFTIRQ通知内核有新frame需要处理。

2. Kernel

Kernel处理input queue。


一次中断,多个Frame

为提高性能,驱动可以持续拷贝frame到input queue,直到指定数量或超过指定时间。例如3c59x.c中vortex_interrupt()函数。

这是驱动自己的事情。

注意:当中断被禁止时,设备在自己的寄存器中保持到来的中断。


NAPI:

驱动 disable 某个有frame到达设备的中断,并让kernel polling驱动的队列。


中断处理程序:

中断处理程序不可抢占,也不可重入。


Softirq (BH):

* 同一类型的softirq可以同时在不同的CPU上运行。

* 同一类型的softirq在同一CPU上只有一个。因此对于per-CPU数据不需加锁,对多CPU共享的数据必须加锁。应尽量使用per-CPU数据以提高并发性。

* softirq的类型是编译时确定死的。

* net有关的softirq:

  NET_TX_SOFTIRQ

  NET_RX_SOFTIRQ

  在net_dev_init()中初始化。

* Kernel检查并处理softirq:

  > local_bh_enable

  > irq_exit (end of do_IRQ)

  > ksoftirqd (per-CPU kernel thread,低优先级)。softirq子系统向 cpu_nfb 内核通知链注册,处理函数是spawn_ksoftirqd,这样当有新CPU时,能spawn新的ksoftirqd。

* softirq运行时,中断是enabled。(进入do_softirq是中断是disabled,处理完pending softirq bitmap后,会打开中断,然后运行softirq handler。)

* 运行在中断Context,无process switch,不会block。但会被中断。

* pending softirq bitmap是per-CPU的。


Tasklet:

* 同一类型的tasklet只运行在一个CPU上,不能在不同的CPU上运行。所以不用考虑并发问题。

* 不同类型的tasklet可以同时运行。

* tasklet类型可以在运行时注册。

* tasklet是softirq: TASKLET_SOFTIRQ,HI_SOFTIRQ。

* 每个CPU都有两个tasklet_vec链表:

  static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec);
  static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec);

  这些链表保存指向tasklet_struct结构的指针,注意tasklet_struct实例不是per-CPU的。所以运行前CPU需要检查一个tasklet_struct是否在其它CPU上调度了。

* tasklet_schedule, tasklet_hi_schedule

  将tasklet_struct加入当前CPU。如果该tasklet已经schedule了(但还没有运行),则这些API什么都不做。


抢占(preemption)被disable的情况:

1. 硬中断和软中断。

2. in scheduler()。

3. spin lock和rw lock段内。


Work Queue:

* 工作在进程上下文(process context)。


关键数据结构 softnet_data

* per-CPU的结构,保存需要处理的ingress队列(input_pkt_queue)。

* 在 net_dev_init()函数中初始化。