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

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

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

理解 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 内核网络数据输入和输出的实现原理。深入源码学习是一个漫长的过程,需要耐心和细致的探索。

相关推荐

Linux 6.15将更新媒体子系统:高通Iris驱动首次亮相

IT之家3月24日消息,科技媒体phoronix昨日(3月23日)发布博文,报道称Linux6.15内核将于本周启动合并窗口,首批提交的PullRequest请求之一,就...

Ubuntu 25.04发行版登场:Linux 6.14内核,带来多项技术革新

IT之家4月18日消息,科技媒体linuxiac昨日(4月17日)发布博文,报道称代号为PluckyPuffin的Ubuntu25.04发行版正式上线,搭载最新Linu...

WordPress 6.8 版本发布:聚焦性能升级,代号“Cecil”

WordPress6.8版本发布:聚焦性能升级,代号“Cecil”全球最受欢迎的内容管理系统(CMS)WordPress正式推出最新版本6.8,代号“塞西尔”(Cecil),以此致敬传奇钢琴家...

Linus Torvalds接受微软Hyper-V升级 下一代Linux启动会更快

虽然Windows的粉丝和Linux的粉丝经常喜欢进行激烈的键盘大战,但操作系统的制造商们自己也了解彼此的优缺点。毫无疑问,微软也明白这一点,事实上,它甚至鼓励用户尝试Linux,尽管是使用...

Debian 12发布:Linux内核升级6.1(debian更新内核)

IT之家6月11日消息,Debian是最古老的GNU/Linux发行版之一,也是许多其他基于Linux的操作系统的基础,包括Ubuntu、Kali、MX和树莓派OS等。这...

Linux Mint预告新功能:升级Nemo搜索、LMDE 7支持OEM安装

IT之家4月10日消息,LinuxMint发布了最新月度简讯,宣布增强Nemo文件管理器的文件搜索功能、Cinnamon桌面环境开始支持Wayland、LMDE7(LinuxM...

Linux 6.2合并大量网络系统更新:推进Wi-Fi 7和800 Gbps网络

IT之家12月15日消息,Linux6.2合并窗口期内已经确认将会合并大量网络子系统更新。和以往版本相同,Linux6.2内核更新周期在网络功能上有大量的改进,更多的细节可以访问这条...

Linux内核升级实践指南(linux内核怎么升级)

Linux内核升级是一个需要谨慎操作的过程,但掌握正确方法后可以显著提升系统性能、安全性或硬件兼容性。以下是一份详细的实践指南,涵盖主流方法及注意事项:一、准备工作查看当前内核版本bashuname...

Linux又将迎来大版本更新 5.20版可能会被称为Linux 6.0

如果你错过了昨天Linux5.19的发布公告,那么这一消息需要回顾一下:被称为Linux5.20的开发中的内核很可能会被称为Linux6.0。根据LinusTorvalds对现代版本的划分,L...

周六的娱乐就是安装一台OracleLinux虚拟机(一)

每个人有每个人的娱乐方式。老父亲可能喜欢摆弄一些机械工具修修补补。我趁着周六安装一套OracleLinux,寓学于乐。在oracle网站上,下载VirtualBox,现在最新版本是7.0.8。在安装过...

Linux系统下Gaussian 16的安装(linux系统如何安装新软件)

Gaussian是目前使用最多的量子化学计算软件,当前最新的版本为Gaussian16C.01。理论上来说Gaussian并不需要安装,因为高斯一般是不出售源代码的,只有二进制文件,以Gaussi...

「Linux基础」VMWare虚拟机安装CentOS后配置静态ip

在VMWare中安装本地虚拟机CentOS7操作系统,动态IP地址会经常变化,不便于管理与实验。为了便于实验,考虑设置成静态IP地址,目标是本地局域网可以通过NAT网关互相访问,且能连接互联网。由于是...

Win10虚拟机,Hyper-V安装CentOS,一次成功

打开控制面板,选择程序选择启用或关闭Windows功能选中Hyper-V下所有的组件。提示我们需要,重启计算机,保存我们的文件,之后点击“立即重新启动”选择开始菜单,输入Hy,就可以打开虚拟机管理器了...

如何在Windows 10中的Hyper-V虚拟机上安装CentOS Linux

注意双重引导的一种可行且相当不错的替代方法是在虚拟机上安装各种操作系统。Microsoft正式支持CentOS作为Hyper-V的来宾OS,并且在安装时可以很好地集成。自CentOS6.4版以来,用...

安装Linux虚拟机的5个理由,以及不安装的5个原因

虚拟机(VM)允许你在不永久更改计算机的情况下探索Linux。如果你对Linux很好奇,但犹豫是否要尝试,VM提供了一个安全、灵活的解决方案。如果这是你第一次听说虚拟机,虚拟机就像“计算机中的计算机”...