博客
关于我
The journey of a packet through the linux 2.4network stack
阅读量:120 次
发布时间:2019-02-26

本文共 2175 字,大约阅读时间需要 7 分钟。

数据包在 Linux 2.4 内核中的传递过程

作者:Harald Welte

日期:2000/10/14 20:27:43

翻译:yunyuaner


2. 接收数据包

2.1 接收中断

当网卡接收到一个与自身硬件地址匹配的或链路层广播的以太网帧时,它会触发一个中断。网卡设备驱动程序负责处理这个中断,通过 DMA/PIO 等方式将数据拷贝到内存中。接着,它申请一个 skb 结构并调用与设备无关的函数 net/core/dev.c:netif_rx(skb)

如果驱动程序未标记时间戳,该函数负责标记时间戳。然后,skb 被添加到适当的队列中进行处理。如果队列已满,数据包会被丢弃。当 skb 被加入接收队列后,接收软件中断会被标记,并在未来某个时间被执行,执行的函数为 include/linux/interrupt.h:__cpu_raise_softirq()。中断处理例程结束后,中断会被重新启用。


2.2 网络接收软件中断

从 2.2 版本以来,序列化底半部被性能优越的软件中断系统取代,传递过程也发生了重大变化。软件中断的最大优点是可以同时在多个 CPU 上执行,而底半部则只能在一个 CPU 上运行。

软件中断的注册位于 net/core/dev.c:net_init()kernel/softirq.c:open_softirq(),后者由软件中断子系统提供。进一步处理数据包的工作由网络接收软件中断(NET_RX_SOFTIRQ)执行,调用函数为 kernel/softirq.c:do_softirq()。这个函数有三个调用点:

  • arch/i386/kernel/irq.c:do_IRQ(),这是通用的 IRQ 处理例程。
  • arch/i386/kernel/entry.S,内核从系统调用返回时调用此处。
  • kernel/sched.c:schedule(),在主进程调度函数中调用。
  • do_softirq() 检测到 NET_RX_SOFTIRQ 被标记时,它会调用 net/core/dev.c:net_rx_action()。在 net_rx_action() 函数中,skb 从接收队列中卸载并分发给适当的数据包处理例程。这里讨论的是 IPv4 数据包,它会被分发给 net/ipv4/ip_input.c:ip_rcv()


    3. IP 数据包处理例程

    3.1 数据包注册

    IP 数据包在 net/core/dev.c:dev_add_pack() 中完成注册。该函数被 net/ipv4/ip_output.c:ip_init() 调用以完成任务。

    3.2 数据包处理

    Linux 内核网络协议栈中,负责处理 IPv4 数据包的函数为 net/ipv4/ip_input.c:ip_rcv()。在初始化检验(如数据包是否针对该主机等)后,IP 检验和被计算出来。其余检验(如数据包长度、协议版本号等)也已完成。

    如果数据包通过了有效性检验,它会被丢弃。如果通过检验,数据包的大小被计算,用于传输介质的无效填充字段被截去。


    4. 数据包路由到其他设备

    如果路由程序决定数据包需要路由到另一台设备,函数 net/ipv4/ip_forward.c:ip_forward() 会被调用。该函数的第一步是检查数据包首部的 TTL。如果 TTL 小于等于 1,则直接丢弃数据包并返回一个 ICMP 超时报文给发送者。

    接下来,检查 skb 的尾空间是否有足够的空间存放目标设备的数据链路层首部。如果没有,skb 进行扩充。然后,TTL 被减 1。如果新数据包的大小大于目标设备的 MTU 且 IP 首部的不分片字段被设置,数据包会被丢弃并返回一个 ICMP 错误报文给发送者。

    最后,调用 netfilter 钩子函数,这里使用的是 NF_IP_FORWARD 钩子。假设 netfilter 钩子函数返回 NF_ACCEPT,则会调用 net/ipv4/ip_forward.c:ip_forward_finish()。该函数检测是否设置了 IP 选项,并用专门的 ip_optFIXME 处理。接着,它调用 include/net/ip.h:ip_send()。如果需要分片,则调用 ip_fragment();否则,继续调用 net/ipv4/ip_forward:ip_finish_output()


    5. 数据包路由到其他设备(续)

    ip_finish_output() 中,函数调用 netfilter NF_IP_POST_ROUTING 钩子,并将接下来的工作交给 ip_finish_output2()。该函数将数据链路层首部添加到 skb 中,然后调用 net/ipv4/ip_output.c:ip_output()

    ip_output() 函数负责将数据包发送到目标设备。它会根据需要分片,并调用相应的函数。如果需要分片,调用 ip_fragment();否则,继续调用 ip_finish_output()


    以上描述了 Linux 2.4.x 内核中 IP 数据包的传递过程。由于从 2.2 版本以来,序列化底半部被性能优越的软件中断系统取代,整个传递过程也随之发生了大的变化。

    转载地址:http://yxdf.baihongyu.com/

    你可能感兴趣的文章
    NETSH WINSOCK RESET这条命令的含义和作用?
    查看>>
    Netty WebSocket客户端
    查看>>
    netty 主要组件+黏包半包+rpc框架+源码透析
    查看>>
    Netty 异步任务调度与异步线程池
    查看>>
    Netty中集成Protobuf实现Java对象数据传递
    查看>>
    Netty事件注册机制深入解析
    查看>>
    Netty原理分析及实战(四)-客户端与服务端双向通信
    查看>>
    Netty客户端断线重连实现及问题思考
    查看>>
    Netty工作笔记0006---NIO的Buffer说明
    查看>>
    Netty工作笔记0007---NIO的三大核心组件关系
    查看>>
    Netty工作笔记0011---Channel应用案例2
    查看>>
    Netty工作笔记0013---Channel应用案例4Copy图片
    查看>>
    Netty工作笔记0014---Buffer类型化和只读
    查看>>
    Netty工作笔记0020---Selectionkey在NIO体系
    查看>>
    Vue踩坑笔记 - 关于vue静态资源引入的问题
    查看>>
    Netty工作笔记0025---SocketChannel API
    查看>>
    Netty工作笔记0027---NIO 网络编程应用--群聊系统2--服务器编写2
    查看>>
    Netty工作笔记0050---Netty核心模块1
    查看>>
    Netty工作笔记0057---Netty群聊系统服务端
    查看>>
    Netty工作笔记0060---Tcp长连接和短连接_Http长连接和短连接_UDP长连接和短连接
    查看>>