关于bpf:网络包的内核漂流记-Part-1-图解网络包接收流程

35次阅读

共计 2757 个字符,预计需要花费 7 分钟才能阅读完成。

注,原文来自 https://blog.mygraphql.com/zh…。如你看到的转载图片不清,请回到原文。

目录

  • 目录
  • 《网络包的内核漂流记》系列介绍

    • 格调、款式、本文的交互浏览形式 📖
  • ISO 网络模型
  • 网络包接管流程概述
  • 网络包接管步骤

    • 初始化与配置
    • IRQ 解决
    • SoftIRQ 中加载网络包到内存
    • SoftIRQ 中推送网络包到下层
  • 结尾
  • 相干

《网络包的内核漂流记》系列介绍

大家晓得,网络数据来源于网线、光纤、无线电波上的比特(bit),而后到网卡,到内核,最初到利用过程 socket。事件如同很简略。但如果是 SRE/DevOps 或是 Performance Engineer,须要做粗疏的监控和优化时,这些显然是不够的。援用本文次要参考作者的原话:

Optimizing and monitoring the network stack is impossible unless you carefully read and understand how it works. You cannot monitor code you don’t understand at a deep level.
除非您仔细阅读并理解其工作原理,否则无奈优化和监控网络堆栈。您无奈深刻监控您不了解的代码。
—— Joe Damato

《网络包的内核漂流记》尝试剖析和跟踪一个网络包在内核各子系统间的流转和触发的合作。

开始前先做个预报,《网络包的内核漂流记》零碎(将)包含:

  • Part 1: 图解网络包接管流程
  • Part 2: BPF 跟踪网络包的内核漂流

    • 我将演示如何用 bpftrace 踪网络包的内核漂流。

为免吓跑人,还是老套路,多图少代码。不过有的图有点点简单。🚜

本系列次要参考:Monitoring and Tuning the Linux Networking Stack: Receiving Data。是的,这是篇被转载、参考到泛滥的文章。简直你能在网上找到的所有讲 Linux 网卡和网络栈收发的文章,都会参考它。但有句话是:

一千个人眼中就有一千个“哈姆雷特”。—— 无名高人

格调、款式、本文的交互浏览形式 📖

尽管不是写书,不过还是阐明一下吧:

  1. 我不打算像八股文的 Linux 内核文章一样,贴一堆源码,让文章看起来内容很饱满但无趣。我用交互 SVG 图片的的办法去援用源码 😎。
  2. https://blog.mygraphql.com/zh… 的原文是 SVG 图片。如果你是在其它中央看到本文,请转回原文。
  3. 正确浏览 SVG 图片的姿态是浏览器中图片处右键,抉择“新 Tab 中关上图片”。
  4. SVG 图片能够点击链接,间接跳转到相应内核源码网页,准确到源码行。 是的,你不须要 git clone 那大陀源码 🤠,只须要一个浏览器就能够。如果你在电脑前开双屏,联合源码和图看,置信我,内核源码不是什么天书,你能看懂大部分的。
  5. 浏览内核源码我用 https://elixir.bootlin.com/li…。这个是很好的内核源码浏览网站,内置源码援用跳转和搜寻性能。

ISO 网络模型

我并不太学院派,但回顾一下基础知识还是必须的:

图:OSI 根本参考模型和 TCP/IP 堆栈之间的逻辑映射,来自这里

下文把第 n 层缩写为 Ln,如 TRANSPORT 层是第 4 层,缩写为 L4

网络包接管流程概述

网络包接管步骤

从代码细节看,网络包接管步骤比拟多。上面划分为 4 步来叙述:

  1. 初始化与配置
  2. IRQ 解决
  3. SoftIRQ 中加载网络包到内存
  4. SoftIRQ 中推送网络包到下层

初始化与配置

首先说说,内核启动时,网络子系统的初始化流程。

  1. 创立 ksoftirqd 内核线程(每个 CPU 一个)
  2. ksoftirqd 线程开始在 run_ksoftirqd 函数中执行它们的解决循环。
  3. 接下来,为每个 CPU 创立一个专用的 softnet_data 对象。。这些对象又援用了其它解决网络数据的重要对象。其中之一是下文会提到 poll_list(轮询列表)。程序通过调用 napi_schedule()函数或来自设施驱动程序的其余 NAPI API 来增加 NAPI 到 poll_list中。
  4. 而后,net_dev_init() 通过调用 open_softirq() 向 softirq 零碎注册 NET_RX_SOFTIRQ 软中断。注册的处理函数称为“net_rx_action()”。这是 softirq 内核线程将执行以解决数据包的函数。

不要心急,第 4 步当前的步骤,将在下文持续。因须要铺垫一下其它内容。

IRQ 解决

上面,从网卡在网络上接管到数据开始,说说后期的包处理过程。

  1. 网卡从网络接收数据。
  2. NIC 应用 DMA 将网络数据写入 RAM。
  3. NIC 拉起 IRQ 位。
  4. 设施驱动之前注册的 IRQ 处理程序被执行。
  5. 革除网卡上的 IRQ,以便它能够为新的数据包达到生成 IRQ。
  6. 通过调用 napi_schedule() 函数,异步触发 NAPI softIRQ 轮询循环。

有了以上铺垫常识后,咱们回头看看上节的「初始化与配置」中未解说的步骤:

5. 驱动中对 napi_schedule() 的调用将驱动的 NAPI poll 对象增加到以后 CPU 的 poll_list 中。
6. 标记 softirq 拉起位,以便这个 CPU 上的 ksoftirqd 过程晓得有数据包要解决。
7. run_ksoftirqd() 函数被调用(由ksoftirq 内核线程循环运行)执行。
8. __do_softirq() 被调用查看softirq 拉起位,看到一个 softIRQ 拉起,并调用拉起位相干的 softIRQ 注册的处理程序:net_rx_action(),后续的网络接收数据所有重要的工作将在这个函数中实现。

SoftIRQ 中加载网络包到内存

这个图比较简单,不多说。

SoftIRQ 中推送网络包到下层

Receive Packet Steering(RPS) 被禁用的状况流程为:

1. netif_receive_skb() 将数据传递给 __netif_receive_core()
6. __netif_receive_core() 将数据传送到 TAP(监听模块) (如 PCAP)。
7. __netif_receive_core() 将数据传递给已注册的协定层处理程序。在大多数状况下,是 IPv4 协定栈注册的 ip_rcv 函数。

应用 Receive Packet Steering(RPS) 的状况流程,这里不说了,我临时未剖析到。

如果你心急,想理解 Receive Packet Steering(RPS) 是什么鬼,那么:

  • https://01.org/linuxgraphics/…
  • https://www.kernel.org/doc/Do…
  • https://www.alibabacloud.com/…

结尾

没太多好说的,好好学习,天天向上。笨人做笨事,做最好的本人。

相干

如果你关注云原生,也应用到 Calico,那么以下这篇兄弟文章你可能喜爱:

  • 一个 IP 包的旅行 —— K8s 网络之 Calico 浅度解构
正文完
 0