文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>linux 2.4网络栈中包的处理过程

linux 2.4网络栈中包的处理过程

时间:2006-01-19  来源:linuxjet

linux 2.4网络栈中包的处理过程

 

作者:Harald Welte [email protected]

原文地址:http://gnumonks.org/ftp/pub/doc/packet-journey-2.4.html


1.4, 2000/10/14 20:27:43

    这篇文档描述了Linux2.4.x内核中包的处理过程。这部分的处理与2.2内核完全不一样,这主要是因为在2.4版本中新的软中断系统彻底替换了下半部的处理机制。

1. 前言

    由于我的能力有限,这篇文档主要是基于一个前提,即x86架构和IP包。

    我对内核的理解也很有限,文章中的错误之处在算难免,请不要对他期望太高,我会很感激你留下意见和建议。

2. 包的接收

2.1 接收中断

    如果网卡收到一个包含本地MAC地址的以太帧或者一个链路层的广播, 他会触发一个中断。这个网卡的驱动会处理这个中断, 会通过DMA/PIO或者其他的方式把包数据读入内存中。他会分配一个skb 结构并调用一个设备无关的协议函数: net/core/dev.c:netif_rx(skb)。

    如果驱动没有在skb上打时间戳, 现在就要打上。随后这个skb进入队列,等待处理器处理。如果此时队列已满,这个包此处会被丢掉。 Skb进入队列以后,软中断会通过(include/linux/interrupt.h:__cpu_raise_softirq())设置运行标记。

   此时这个中断处理退出,其他的中断恢复汇报状态。

2.2 网络收包软中断

    2.2和2.4内核存在很大的不同,整个网络栈不再是一个下半部, 而是一个软中断。软中断区别于下半部的主要的优点是他可以运行在多个CPU上。

    我们的网络接受软中断在net/core/dev.c:net_init()函数中通过软中断系统提供的kernel/softirq.c:open_softirq()函数进行注册。

    更进一步对包的处理在通过kernel/softirq.c:do_softirq()调用的软中断(NET_RX_SOFTIRQ)中处理。 do_softirq()自身在内核中有三个地方被调用:

  1. 在arch/i386/kernel/irq.c:do_IRQ()中, 这是通常的IRQ处理函数。
  2. 在arch/i386/kernel/entry.S 中,内核刚从一个系统调用返回的时候。
  3. 在主要的处理调度程序中kernel/sched.c:schedule()。

    只要运行到上述三个地方中的任何一个, do_softirq()函数就会被调用, 他会检测到NET_RX_SOFTIRQ标记并调用net/core/dev.c:net_rx_action()函数。在这里skb从CPU接收队列中被取出,随后在适当的包处理函数中进行处理。 对于IPv4来说,就是IPv4包处理函数。

2.3 IPv4包处理函数

    IP包处理函数在net/ipv4/ip_output.c:ip_init()中通过net/core/dev.c:dev_add_pack()注册。

   IPv4包处理函数是net/ipv4/ip_input.c:ip_rcv()。 一些初始的检查以后(是否该包是针对本机的, ...)  IP 校验和被计算出来。另外,会对包长和IP协议版本4进行检查。

    任何没有通过这些检查的包都将在这里被丢弃。

    如果包通过了这些检查, 如果传输介质附加了一些信息,我们需要重新计算IP包的大小并相应的调整skb结构。

    在这里Netfilter钩子第一次被调用。

    Netfilter对标准的路由代码提供了一个通常而又抽象的接口,主要用来进行包过滤,破坏性处理,地址转换和用户空间的包排队。要获取关于Netfilter更详细的信息可以参考我的会议文档 'Linux2.4 netfilter 子系统' 或者 Rustys的一份不可靠文档中, 那就是netfilter 进阶向导。

    包成功到达Netfilter以后, 会调用net/ipv4/ipv_input.c:ip_rcv_finish() 函数.

    在ip_rcv_finish()函数里面, 包的目的地通过调用路由函数来决定(net/ipv4/route.c:ip_route_input())来决定。而且, 如果我们的IP包有IP项, 他们会马上被处理,根据net/ipv4/route.c:ip_route_input_slow()函数做出的路由结果, 我们的包会继续进入到下面的一个函数中接受处理:

net/ipv4/ip_input.c:ip_local_deliver()

如果包的目的地是本机地址, 我们对它进行协议处理并将它发送到用户态进程,这个函数就是用来做这个的。

net/ipv4/ip_forward.c:ip_forward()

如果包的目的地不是本地, 我们把它转送到另一个网络,这个函数将完成这个任务。

net/ipv4/route.c:ip_error()

如果错误发生, 我们又不能为这个包找到一条适当的路由表项,包将会进入这个函数接受处理。

net/ipv4/ipmr.c:ip_mr_input()

如果是个多播包并且我们设定了多播路由,包将会进入这个函数接受处理。

3. 向另一个设备转发包

    如果路由以后决定将该包发送到另一个设备,那末会调用net/ipv4/ip_forward.c:ip_forward() 函数来完成这个操作。

    这个函数的第一个任务是用来检查IP头的TLL值。如果这个值小于等于1,我们会丢弃这个包并给发送者返回ICMP过期信息。

    如果空间足够我们会检查包头我们检查目的设备的链路头并展开skb结构。

    下一步要对 TTL减一。

    如果我们的新包大于目的设备的MTU, 这是IP头的未分片位会被设置,随后丢弃这个包向发送者发送ICMP需要分片的信息。

    最后需要丢用另一个netfilter 的钩子- NF_IP_FORWARD 钩子。

    设定netfilter 钩子返回一个 NF_ACCEPT的决定, 那末下一步这个包会进入net/ipv4/ip_forward.c:ip_forward_finish() 函数进行处理。

    ip_forward_finish() 自己会检查是否我们需要在IP头设置任何额外的选项, ip_optFIXME 来负责这个事情。 随后调用include/net/ip.h:ip_send()函数。

    如果我们需要分片, FIXME:ip_fragment 会被调用, 然后我们继续调用net/ipv4/ip_forward:ip_finish_output()函数。

    ip_finish_output() 只是重复调用netfilter postrouting 钩子NF_IP_POST_ROUTING,如果这个钩子返回成功的话ip_finish_output2()函数会被调用。

    ip_finish_output2() 会预先处理我们skb中的硬件头(链路层) 部分并调用net/ipv4/ip_output.c:ip_output()函数。


排行榜 更多 +
哥布林弹球b服手游下载

哥布林弹球b服手游下载

休闲益智 下载
小马样式盒游戏下载

小马样式盒游戏下载

休闲益智 下载
异变小镇中文版下载安装

异变小镇中文版下载安装

冒险解谜 下载