百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

从源码解析linux内核中如何实现网络数据的输入和输出

ahcoder 2025-04-05 16:23 42 浏览

理解 Linux 内核如何处理网络数据的输入和输出,需要深入到内核网络协议栈的源码中。这是一个复杂的过程,涉及到多个子系统和数据结构。下面我将从源码层面解析 Linux 内核网络数据输入和输出的主要流程和关键点,并提供一些相关的源码位置,希望能帮助你理解。

核心数据结构:sk_buff (Socket Buffer)

在深入流程之前,必须先了解 sk_buff。它是 Linux 内核网络子系统中最核心的数据结构,用于表示网络数据包。sk_buff 结构体包含了:

  • 数据缓冲区: 存储实际的网络数据包内容。
  • 元数据: 包含数据包的各种信息,例如:网络协议层信息 (例如,IP 头部、TCP 头部等)网络设备信息 (例如,接收/发送的网络接口)状态信息 (例如,错误状态、校验和状态等)时间戳QoS (服务质量) 信息… 等等

sk_buff 就像一个容器,在网络协议栈的各个层之间传递,并被不断地添加和修改元数据。

网络数据输入 (接收)

网络数据输入路径通常从网卡 (Network Interface Card, NIC) 接收到数据包开始,一直到数据包被传递给用户空间的应用程序。主要流程如下:

  1. 网卡接收数据包并触发中断 (Interrupt):
  2. 当网卡接收到网络数据包时,它会通过 DMA (Direct Memory Access) 将数据包写入到系统内存的接收缓冲区 (Receive Buffer)。
  3. 网卡会向 CPU 发送中断信号,通知 CPU 有新的数据包到达。
  4. 源码位置: 网卡驱动程序 (通常在 drivers/net/ethernet/ 目录下) 的中断处理函数。
  5. 中断处理程序 (Interrupt Handler):
  6. CPU 响应中断后,会执行网卡驱动程序注册的中断处理程序。
  7. 中断处理程序的主要任务是快速确认中断,并尽可能快地将数据包的处理工作移交给下半部 (Bottom Half) 或软中断 (SoftIRQ)。
  8. 源码位置: 网卡驱动程序的中断处理函数,例如 net_interrupt (在 drivers/net/ethernet/ 目录下查找你的网卡驱动)。
  9. 软中断 (SoftIRQ) 或下半部 (Bottom Half) 处理:
  10. 为了避免中断处理程序占用 CPU 时间过长,耗时较长的网络数据包处理工作通常在软中断或下半部中完成。
  11. Linux 内核使用 NET_RX_SOFTIRQ 软中断来处理网络数据包的接收。
  12. 源码位置: net/core/dev.c 中的 net_rx_action 函数是 NET_RX_SOFTIRQ 的处理函数。
  13. net_rx_action 函数 (软中断处理函数):
  14. net_rx_action 函数从每个 CPU 的 per-CPU 接收队列 (percpu_dev_state->rx_queue) 中取出 sk_buff。
  15. 它会遍历注册到网络设备上的协议处理函数 (ptype_base),找到合适的协议处理函数来处理 sk_buff。
  16. 源码位置: net/core/dev.c 中的 net_rx_action 函数。
  17. 协议解复用 (Protocol Demultiplexing):
  18. net_rx_action 函数通过 eth_type_trans 函数根据数据链路层头部 (例如,以太网头部) 中的协议类型字段 (EtherType) 来判断上层协议类型 (例如,IP、ARP 等)。
  19. 然后,它会调用 __netif_receive_skb 或 __netif_receive_skb_core 函数,根据协议类型找到对应的协议处理函数。
  20. 源码位置:net/ethernet/eth.c 中的 eth_type_trans 函数net/core/dev.c 中的 __netif_receive_skb 和 __netif_receive_skb_core 函数
  21. 协议栈处理 (Protocol Stack Processing):
  22. 根据协议类型,数据包会被传递到相应的协议栈处理函数,例如:IP 协议: net/ipv4/ip_input.c 中的 ip_rcv 函数ARP 协议: net/arp/arp.c 中的 arp_rcv 函数
  23. 这些协议处理函数会进行协议头部的解析、校验、路由查找、协议相关的处理 (例如,IP 分片重组、TCP 连接管理等)。
  24. 源码位置:net/ipv4/ip_input.c 中的 ip_rcv 函数 (IP 协议)net/arp/arp.c 中的 arp_rcv 函数 (ARP 协议)net/ipv6/ip6_input.c 中的 ip6_rcv 函数 (IPv6 协议)net/ipv4/tcp_input.c 中的 tcp_v4_rcv 函数 (TCP 协议)net/ipv4/udp.c 中的 udp_rcv 函数 (UDP 协议)
  25. 传输层处理 (Transport Layer Processing):
  26. 对于 TCP 和 UDP 协议,数据包会被传递到传输层处理函数 (例如 tcp_v4_rcv, udp_rcv)。
  27. 传输层处理函数会进行端口解复用,根据目标端口号找到对应的 socket。
  28. 对于 TCP,还会进行连接状态管理、流量控制、拥塞控制等。
  29. 源码位置:net/ipv4/tcp_input.c 中的 tcp_v4_rcv 函数 (TCP 协议)net/ipv4/udp.c 中的 udp_rcv 函数 (UDP 协议)
  30. Socket 层处理 (Socket Layer Processing):
  31. 找到对应的 socket 后,数据包会被放入 socket 的接收队列 (sk_receive_queue)。
  32. 用户空间的应用程序可以通过 recv(), read() 等系统调用从 socket 接收队列中读取数据。
  33. 源码位置:net/socket.c 中的 sock_queue_rcv_skb 函数 (将 sk_buff 放入 socket 接收队列)net/socket.c 中的 sys_recvfrom (系统调用 recvfrom 的内核实现)

网络数据输出 (发送)

网络数据输出路径通常从用户空间的应用程序发起 send(), write() 等系统调用开始,一直到数据包被网卡发送出去。主要流程如下:

  1. 用户空间应用程序发起发送系统调用:
  2. 应用程序调用 send(), write(), sendto(), sendmsg() 等系统调用来发送数据。
  3. 这些系统调用会进入内核空间。
  4. 源码位置: 例如 net/socket.c 中的 sys_sendto (系统调用 sendto 的内核实现)。
  5. Socket 层处理 (Socket Layer Processing):
  6. 系统调用处理函数 (例如 sys_sendto) 会找到与应用程序关联的 socket。
  7. 它会从用户空间复制数据到内核空间,并创建一个或多个 sk_buff 来存储要发送的数据。
  8. 源码位置: net/socket.c 中的 sock_sendmsg 函数 (socket 层发送消息的核心函数)。
  9. 传输层处理 (Transport Layer Processing):
  10. 对于 TCP 和 UDP 协议,数据包会被传递到传输层处理函数 (例如 tcp_sendmsg, udp_sendmsg)。
  11. 传输层处理函数会添加传输层头部 (例如,TCP 头部、UDP 头部),并进行协议相关的处理 (例如,TCP 连接管理、流量控制、拥塞控制等)。
  12. 源码位置:net/ipv4/tcp.c 中的 tcp_sendmsg 函数 (TCP 协议)net/ipv4/udp.c 中的 udp_sendmsg 函数 (UDP 协议)
  13. 网络层处理 (Network Layer Processing):
  14. 数据包会被传递到网络层处理函数 (例如 ip_queue_xmit, ip6_queue_xmit)。
  15. 网络层处理函数会进行路由查找,确定下一跳的 IP 地址和网络接口。
  16. 它会添加网络层头部 (例如,IP 头部),并进行 IP 分片 (如果需要)。
  17. 源码位置:net/ipv4/ip_output.c 中的 ip_queue_xmit 函数 (IPv4 协议)net/ipv6/ip6_output.c 中的 ip6_queue_xmit 函数 (IPv6 协议)net/ipv4/route.c 中的 ip_route_output_flow 函数 (路由查找)
  18. 数据链路层处理 (Data Link Layer Processing):
  19. 数据包会被传递到数据链路层处理函数 (例如 dev_queue_xmit)。
  20. 数据链路层处理函数会根据网络接口的类型添加数据链路层头部 (例如,以太网头部)。
  21. 它会进行 ARP 解析 (如果目标 MAC 地址未知),获取目标 MAC 地址。
  22. 源码位置: net/core/dev.c 中的 dev_queue_xmit 函数。
  23. 设备驱动程序处理 (Device Driver Processing):
  24. 数据包会被传递到网络设备驱动程序的发送函数 (例如 ndo_start_xmit)。
  25. 驱动程序会将 sk_buff 中的数据准备好,通过 DMA 将数据写入到网卡的发送缓冲区 (Transmit Buffer)。
  26. 驱动程序会通知网卡发送数据包。
  27. 源码位置: 网卡驱动程序的发送函数,例如 ndo_start_xmit (在 drivers/net/ethernet/ 目录下查找你的网卡驱动)。
  28. 网卡发送数据包:
  29. 网卡从发送缓冲区读取数据,并将数据包发送到网络介质 (例如,网线、无线电波)。

关键源码文件和目录:

  • include/linux/skbuff.h: sk_buff 结构体的定义。
  • net/core/dev.c: 网络设备核心代码,包括 net_rx_action, dev_queue_xmit, __netif_receive_skb 等关键函数。
  • net/socket.c: Socket 层核心代码,包括 sock_sendmsg, sock_queue_rcv_skb, sys_sendto, sys_recvfrom 等系统调用实现。
  • net/ipv4/ 和 net/ipv6/: IPv4 和 IPv6 协议栈的实现,包括 ip_input.c, ip_output.c, tcp_input.c, udp.c 等。
  • net/ethernet/: 以太网协议相关的代码,包括 eth.c (以太网头部处理) 和各种以太网网卡驱动程序。
  • drivers/net/ethernet/: 各种以太网网卡驱动程序的目录。

总结:

Linux 内核网络数据的输入和输出是一个复杂而精细的过程,涉及到多个层次的协议栈和驱动程序。理解这个过程的关键在于:

  • sk_buff 数据结构: 它是网络数据包在内核中传递的载体。
  • 中断和软中断机制: 用于高效地处理网络数据包的接收。
  • 协议栈分层处理: 数据包在不同的协议层 (数据链路层、网络层、传输层) 被逐层处理和封装/解封装。
  • Socket 层作为用户空间和内核空间的接口: 应用程序通过 Socket 系统调用与内核网络协议栈进行交互。

学习建议:

  • 从 sk_buff 开始: 深入理解 sk_buff 结构体的各个字段和作用。
  • 跟踪数据包的流动: 从网卡驱动程序的中断处理函数开始,逐步跟踪数据包在内核协议栈中的流动路径,理解每个阶段的处理逻辑。
  • 阅读关键源码文件: 重点阅读上面列出的关键源码文件,结合代码注释和相关文档进行学习。
  • 使用调试工具: 可以使用 tcpdump, wireshark, netstat 等工具抓包和分析网络数据,结合内核调试工具 (例如 printk, kprobe, ftrace) 来跟踪内核代码的执行流程。

希望这个解析能够帮助你理解 Linux 内核网络数据输入和输出的实现原理。深入源码学习是一个漫长的过程,需要耐心和细致的探索。

相关推荐

KaOS 2025.05版本发布:全面拥抱Qt6,彻底告别Qt5

KaOSLinux2025.05版本重磅发布:全面拥抱Qt6,开启KDE生态新篇章继2025.03版本发布两个月后,专注于KDE桌面环境、采用XFS文件系统的滚动发行版Li...

基于FIMC接口的CMOS摄像头驱动分析与设计

摘要:目前的嵌入式系统中,USB摄像头使用比较普遍,但其应用会受到传输速度的限制。本文采用一款高速CMOS摄像头,其驱动利用S3C6410内置的FIMC接口技术,采用DMA和ping-pong缓冲...

没错是微软 推出基于Linux的交换机系统

2015-09-2205:59:59作者:郑伟你没看错,为了提升自身Azure云数据中心内网络设备的兼容性及开放性,微软也开始推出基于Linux的网络交换机系统了。这个被称为AzureCloud...

Linus Torvalds 宣布首个 Linux 内核 6.16 候选版本

Linux内核负责人兼创始人LinusTorvalds宣布关闭合并窗口,该窗口用于将主要新功能添加到内核中,并开始发布Linux6.16候选版本,从候选版本1(Linux6.16-r...

Linux内核漏洞将影响Haswell架构服务器

在infoq网站上,GilTene最近报告一个十分重要,但并不为人知Linux内核补丁,特别对采用Haswell架构的Linux系统用户和管理员应该特别关注。报告提醒RedHat发行版的用户(包括...

关于Linux性能调优中网络I/O的一些笔记

写在前面和小伙伴分享一些Linux网络优化的笔记,内容很浅,可以用作入门博文内容结合《Linux性能优化》读书笔记整理涉及内容包括常用的优化工具(mii-tool,ethtool,ifconfig,i...

国产操作系统- Veket Linux(国产操作系统之光银河麒麟阅读理解)

VeketLinux是一个随身的可装在U盘的Linux操作系统。主要面向桌面用户。它的设计重点是提供简单易用且稳定的操作系统,同时保持更新和开发。它具有强大的功能集和广泛的用户基础,可满足...

AlmaLinux 9.6发布:升级工具、初步支持IBM Power虚拟化技术

IT之家5月21日消息,科技媒体linuxiac昨日(5月20日)发布博文,报道称代号为SageMargay的AlmaLinux9.6发行版已上线,距上一版本9.5发...

跟老韩学Linux运维架构师系列,vim与view的基本使用

下面是vim和view的10个实例:用vim打开一个新文件:vimnewfile.txt这个命令将会在vim编辑器中打开一个新文件。在vim中移动光标:使用方向键或h、j、k、l键来移动光标。在v...

malloc底层原理剖析——ptmalloc内存池

malloc底层为什么是内存池malloc大家都用过,其是库函数。我们都知道库函数在不同的操作系统中其实执行的是系统调用,那么malloc在Linux上执行的是哪个系统调用呢?brk()和mmap()...

Zen 6架构首秀Linux,AMD加速下一代处理器布局

IT之家5月15日消息,科技媒体Phoronix昨日(5月14日)发布博文,报道称AMD已经开始为下一代“Zen6”处理器做准备,已为该构架向Linux内核提交了首个补丁,...

为何越来越多企业转向安卓/Linux工业平板电脑?答案在这里

在工业领域,设备的稳定性至关重要,尤其是工业平板电脑,常年运行在高温、粉尘、潮湿等复杂环境下,一旦系统崩溃或者卡顿,可能会影响整个生产流程。那么,为什么越来越多的企业选择安卓/Linux工业平板电脑,...

从3ms到0.8ms:ARM+Linux如何重塑工业控制实时性标杆

在智能制造领域,产线控制系统对实时性的要求越来越高。根据行业调研数据,超过65%的工业现场出现过因系统响应延迟导致的故障停机,平均每次停机造成的直接损失高达2-8万元。传统x86架构搭配Windows...

看Linux如何"挖坑种树"

写在前面,有人看我的Linux文章说技术难度不深,笔者不是不想写深,笔者是觉得Linux难就难在入门,入门之后你就知道如何上网查询你所要要解决的Linux需求。如果你已入门,此文已对你无用,请略过此...

AlmaLinux 9.6 发布,新增功能亮点纷呈!

距离上一版本AlmaLinux9.5发布六个月后,基于5.14内核的AlmaLinux正式宣布其企业级Linux发行版的9.x系列第六个更新——AlmaLinux9.6(Sag...