Linux 网络收包流程
0赞我们在跟别人网上聊天的时候,有没有想过你发送的信息是怎么传到对方的电脑上的
又或者我们在上网冲浪的时候,有没有想过 HTML 页面是怎么显示在我们的电脑屏幕上的
无论是我们跟别人聊天还是上网冲浪,其实都依靠于计算机网络这项技术
计算机网络是指将多台计算机通过通信设备和传输介质连接在一起,使得它们之间能够相互通信、资源共享和协同工作
而计算机之间是通过数据包来实现信息传输和信息交换的,数据包是计算机网络中传输数据的基本单位
今天咸鱼将以 Linux 为例来给大家介绍一下 Linux 是如何实现网络接收数据包
网络协议栈&网络架构
在正文开始之前,我们先来了解一下 Linux 中的网络协议模型和网络子系统
网络协议模型(网络协议栈)
在 Linux 中,Linux 网络协议栈分成了五层
其中:
应用层提供 socket 接口来供用户进程访问内核空间的网络协议栈
传输层、网络层协议由 Linux 内核网络协议栈实现
链路层协议靠网卡驱动来实现
物理层协议由硬件网卡实现
网络子系统(网络架构)
网络子系统是 Linux 内核中的一部分,由多个模块和驱动程序组成,它负责管理和控制系统的网络功能以实现网络通信
通过 Linux 网络子系统(网络架构)来实现上述网络协议模型
其中
System call interface:为应用程序获取内核的网络系统提供了接口,例如 socket
Protocol agnostic interface:为和各种传输层协议的网络交互提供的一层公共接口
Network protocals:对各种传输层协议的实现,如 TCP、UDP、IP 等
Device agnostic interface:为各种底层网络设备抽象出的公共接口,与各种网络设备驱动连接在一起
Device drivers:与各种网络设备交互的驱动
收包过程
当 Linux 接收一个数据包的时候,这个包是怎么经过 Linux 的内核从而被应用程序拿到的呢?
到达网卡(NIC,Network Interface Card)
首先数据包到达网卡之后,网卡会校验接收到的数据包中的目的 MAC 地址是不是自己的 MAC 地址,如果不是的话通常就会丢弃掉
这种只接受发送给自己的数据包(其余的扔掉)的工作模式称为非混杂模式(Non-Promiscuous Mode)
混杂模式(Promiscuous Mode)则是网卡会接收通过网络传输的所有数据包,而不仅仅是发送给它自己的数据包
非混杂模式是网卡默认的工作模式,可以尽可能的保护网络安全和减少网络负载
网卡在校验完 MAC 地址之后还会校验数据帧(Data Frame)中校验字段 FCS 来一次确保接收到的数据包是正确的
网卡硬件缓冲区 ——> 系统内存(ring buffer)
当网卡接收到数据包时,它将数据包的内容存储在硬件缓冲区中,然后通过 DMA 将接收到的数据从硬件缓冲区传输到系统内存中的指定位置,这个位置通常是一个环形缓冲区( ring buffer)
DMA(直接内存访问,Direct Memory Access)
DMA是一种数据传输技术,允许外设(如网卡、硬盘控制器、显卡等)直接访问计算机内存,而无需经过 CPU
通过 DMA 可以大大提高数据传输的效率,减轻 CPU 的负担
触发硬中断
当网卡将数据包 DMA 到用于接收的环形缓冲区(rx_ring)之后,就会触发一个硬中断来告诉 CPU 数据包收到了
什么时候会触发一个硬中断,可以通过下面的参数来进行配置:
rx-usecs:当过这么长时间过后,一个中断就会被产生
rx-frames:当累计接收到这么多个数据帧后,一个中断就会被产生
上面的参数配置可以通过下面的命令来查看
总结
网络模块可以说是 Linux 内核中最复杂的模块了
看起来一个简简单单的收包过程就涉及到许多内核组件之间的交互,如网卡驱动、协议栈,内核ksoftirqd 线程等
咸鱼原本打算把收包和发包的流程都写上的,但是光是写收包流程就就要了我半条命了,等下次有机会把发包的流程也写一下
总结一下 Linux 网络收包流程:
数据到达网卡之后,网卡通过 DMA 将数据放到内存分配好的一块 ring buffer 中,然后触发硬中断
CPU 收到硬中断之后简单的处理了一下(分配 skb_buffer),然后触发软中断
软中断进程 ksoftirqd 执行一系列操作(例如把数据帧从 ring ruffer上取下来)然后将数据送到三层协议栈中
在三层协议栈中数据被进一步处理发送到四层协议栈
在四层协议栈中,数据会从内核拷贝到用户空间,供应用程序读取
最后被处在应用层的应用程序去读取
原文链接:https://mp.weixin.qq.com/s/GqEdfE1fJI5t8ZQ_0Bj-Ww
电子技术应用专栏作家 一口Linux