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。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 static int __init net_dev_init(void) { ... ... for_each_possible_cpu(i) { struct softnet_data *sd = &per_cpu(softnet_data, i); memset(sd, 0, sizeof(*sd)); skb_queue_head_init(&sd->input_pkt_queue); skb_queue_head_init(&sd->process_queue); sd->completion_queue = NULL; INIT_LIST_HEAD(&sd->poll_list); sd->output_queue = NULL; sd->output_queue_tailp = &sd->output_queue; #ifdef CONFIG_RPS sd->csd.func = rps_trigger_softirq; sd->csd.info = sd; sd->csd.flags = 0; sd->cpu = i; #endif sd->backlog.poll = process_backlog; sd->backlog.weight = weight_p; sd->backlog.gro_list = NULL; sd->backlog.gro_count = 0; } ... open_softirq(NET_TX_SOFTIRQ, net_tx_action); open_softirq(NET_RX_SOFTIRQ, net_rx_action); out: return rc; } subsys_initcall(net_dev_init); 网络子系统初始化的核心是为每个 CPU 都申请了一个 softnet_data数据结构,并且为网络中断注册了对应的处理函数,其中 NET_TX_SOFTIRQ 的处理函数是 net_tx_action, NET_RX_SOFTIRQ的处理函数是net_rx_action。中断和其对应的处理函数之间是如何对应的可以跟踪阅读 open_softirq。 ...... 通过阅读本文应该能够知悉: ...

发表于:2024-09-01 · 更新于: 2024-09-01

Linux 网络 —— 数据包的接收

背景 最初学习计算机网络的时候,通常都是从 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。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 static int __init net_dev_init(void) { ... ... for_each_possible_cpu(i) { struct softnet_data *sd = &per_cpu(softnet_data, i); memset(sd, 0, sizeof(*sd)); skb_queue_head_init(&sd->input_pkt_queue); skb_queue_head_init(&sd->process_queue); sd->completion_queue = NULL; INIT_LIST_HEAD(&sd->poll_list); sd->output_queue = NULL; sd->output_queue_tailp = &sd->output_queue; #ifdef CONFIG_RPS sd->csd.func = rps_trigger_softirq; sd->csd.info = sd; sd->csd.flags = 0; sd->cpu = i; #endif sd->backlog.poll = process_backlog; sd->backlog.weight = weight_p; sd->backlog.gro_list = NULL; sd->backlog.gro_count = 0; } ... open_softirq(NET_TX_SOFTIRQ, net_tx_action); open_softirq(NET_RX_SOFTIRQ, net_rx_action); out: return rc; } subsys_initcall(net_dev_init); 网络子系统初始化的核心是为每个 CPU 都申请了一个 softnet_data数据结构,并且为网络中断注册了对应的处理函数,其中 NET_TX_SOFTIRQ 的处理函数是 net_tx_action, NET_RX_SOFTIRQ的处理函数是net_rx_action。中断和其对应的处理函数之间是如何对应的可以跟踪阅读 open_softirq。 ...

发表于:2024-08-24 · 更新于: 2024-08-24

rsync 用法

在不同的机器和服务器之间进行数据同步是一个常见的场景,也有不同的命令工具(如 scp、FTP 等),甚至是不同的图形界面软件(如 Termius 等)可供我们选择操作。本文记录的 rsync (remote sync)也是用于文件同步的工具之一,其最大的特点是会检查发送方和接收已有的文件,并仅传输有变动的部分。rsync 不仅可以在本地不同的目录之间使用,同时也支持本地主机与远程服务器之间进行数据同步。由于其具有仅传输变动、增量备份、 断点续传等特点,在一些场景下非常实用。本文记录了其一些常见的用法,主要关注其在本地主机与远程主机之间同步的操作。 在使用 rysnc 之前需要确保本地和远程主机都安装了 rsync,可通过 rsync --version 检查是否安装,如果没有,可使用下面的命令进行安装: 1 2 sudo apt-get install rsync # ubuntu brew install rsync # macOS rsync 的基本使用如下: 1 2 3 4 rsync -av [source] [destination] -a: 表示递归同步,并同步元信息 -v: 输出到终端 如果目标位置不存在,执行上诉命令之后将会自动创建。 常用参数 -n 如果不确定执行 rsync 会有什么结果,可以使用该参数查看执行后的结果,并不真正执行命令。 --delete 默认情况下,rsync 只是将源目录的所有内容都复制到目标目录,并不会保证两个目录相同,也不会删除文件。因此,如果是想要构建源目录的镜像就需要使用 --delete 参数,这样保证目标目录和源目录相同。 --exclude --exclude参数用于排除文件或者目录,利用该参数指定排除模式。排除多个模式的文件时,可以使用 Bash 的扩展功能。如果需要排除的文件数量比较多,那么可以将其需要排除的文件所对应的模式写入文件,每个模式负责一行,然后利用 --exclude-from 参数指定文件。 与 --exclude 参数所类似的有 --include 参数,用于指定必须同步的文件,二者一般联合使用。 增量备份 rsync 的最大特点就是它可以完成增量备份。除了源目录与目标目录直接比较,rsync 还支持使用基准目录,即将源目录与基准目录之间变动的部分,同步到目标目录。 ...

发表于:2023-04-20 · 更新于: 2023-04-20

Linux 60秒性能分析

原文:Linux Performance Analysis in 60,000 Milliseconds 当你登陆到一台性能出现问题的 Linux 服务器:你在第一分钟会检查什么? 在 Netflix,我们拥有一个庞大的 EC2 Linux 云和大量的性能分析工具,用于监控和调查其性能。其中包括 Atlas 用于云范围的监控和 Vector 用于按需实例分析。虽然这些工具帮助我们解决了大多数问题,但有时我们需要登录到一台实例并运行一些标准的 Linux 性能工具。 60秒摘要 这篇文章将介绍 Netflix 性能工程团队在命令行下使用标准 Linux 工具进行优化性能调查的前60秒,你也可以使用这些工具。在60秒内,你可以通过运行以下十个命令了解系统资源使用情况和正在运行的进程。查找错误和饱和度指标,然后查看资源利用率。饱和是指资源的负载超过其处理能力,可表现为请求队列的长度或等待时间。 1 2 3 4 5 6 7 8 9 10 uptime dmesg | tail vmstat 1 mpstat -P ALL 1 pidstat 1 iostat -xz 1 free -m sar -n DEV 1 sar -n TCP,ETCP 1 top 其中一些命令需要安装 sysstat 软件包。这些命令输出的指标将有助于完成一些性能瓶颈的定位(USE 方法)。这涉及检查所有资源(CPU,内存,磁盘等)的利用率、饱和度和错误指标。还要注意何时检查和排除了资源,因为通过排除,可以缩小要研究的目标,并指导任何后续的分析。 ...

发表于:2023-03-19 · 更新于: 2023-03-19