博客
关于我
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/

    你可能感兴趣的文章
    Navicat for MySQL 查看BLOB字段内容
    查看>>
    Neo4j电影关系图Cypher
    查看>>
    Neo4j的安装与使用
    查看>>
    Neo4j(2):环境搭建
    查看>>
    Neo私链
    查看>>
    nessus快速安装使用指南(非常详细)零基础入门到精通,收藏这一篇就够了
    查看>>
    Nessus漏洞扫描教程之配置Nessus
    查看>>
    Nest.js 6.0.0 正式版发布,基于 TypeScript 的 Node.js 框架
    查看>>
    NetApp凭借领先的混合云数据与服务把握数字化转型机遇
    查看>>
    NetBeans IDE8.0需要JDK1.7及以上版本
    查看>>
    netcat的端口转发功能的实现
    查看>>
    netfilter应用场景
    查看>>
    netlink2.6.32内核实现源码
    查看>>
    Netpas:不一样的SD-WAN+ 保障网络通讯品质
    查看>>
    NetScaler的常用配置
    查看>>
    netsh advfirewall
    查看>>
    NETSH WINSOCK RESET这条命令的含义和作用?
    查看>>
    Netty WebSocket客户端
    查看>>
    netty 主要组件+黏包半包+rpc框架+源码透析
    查看>>
    Netty 异步任务调度与异步线程池
    查看>>