Linux 网络 —— 数据包的发送
背景 Linux 网络–数据包的接收 一文中分析了 Linux 是如何接收一个数据包的,那么 Linux 在发送数据包的时候又是什么样的呢?本文聚焦于 Linux 数据包的发送,结合内核源码分析数据包的发送过程。 关于 Linux 网络数据包的接收可以阅读前文: Linux 网络 —— 数据包的接收 日期: 2024-08-24 标签: #Linux #net 背景 最初学习计算机网络的时候,通常都是从 TCP/IP 网络分层模型入手,学习各种协议,如 TCP、IP等,以及相关的原理,并未过多关注整个协议栈具体是如何实现的。在开发的过程中,通过高级语言往往只需要几行就能实现一个简单的网络程序,并从网络接收数据。然而数据具体是如何从网卡达到我们的进程中的呢?在这个过程中网卡和内核到底又做了些什么呢?数据在这个过程中是如何流转、复制的呢?带着这些问题,笔者最近学习了下 Linux 网络数据包的接收,并总结如下。 通过阅读本文应该能够了解: Linux 网络栈是如何接收数据的,数据从网卡到内核各个部分是如何进行流转的; 网络栈在正式工作之前需要经过哪些初始化,这些初始化工作的目的是什么; 数据包从网卡到内核需要经过几次复制; 网络相关的硬中断、软中断分别是如何实现的,二者是如何配合的; ethtool、tcpdump、iptables 等分别工作在何处,原理是什么。 本文基于内核 3.10 版本,网卡举例使用的是 igb 网卡。 <!DOCTYPE html> 系统初始化 Linux 系统在接收数据包之前需要做很多的准备工作,比如创建内核 ksoftirqd 线程,便于后续处理软中断;网络子系统初始化,注册各个协议的处理函数,便于后面的协议栈处理;网卡设备子系统初始化,便于后面从网卡接收数据包。这里首先对这些初始化的过程进行记录,其中重点是网卡设备的初始化。 内核线程 ksoftirqd 初始化 Linux 在接收网络数据的时候需要用到中断机制,包括硬中断和软中断。 其中 Linux 的软中断都是在内核线程 ksoftirq 中进行的,该线程在系统中有 N 个 (N=机器核数),线程被 CPU 调度。 系统初始化的时候创建了这一线程,之后它就进入到这自己的线程循环函数 ksoftirqd_should_run 和 run_ksoftirqd,判断有无中断需要处理。这里的中断不仅仅包括网络相关的软中断,还有其他的中断类型, 具体可以查看 Linux 的定义。 关于Linux中断相关的原理与实现,推荐阅读下面这篇文章: Linux 中断(IRQ/softirq)基础:原理及内核实现(2022) 网络子系统初始化 Linux 内核通过 subsys_initcall调用来初始化各个子系统,这里我们来看一看网络子系统的初始化 net_dev_init。 static int __init net_dev_init(void) { . ...