Linux网络协议栈
2021-07-10 00:00:06 1 举报
Linux网络协议栈,应用程序到硬件全流程
作者其他创作
大纲/内容
网卡NIC接收队列
3 CPU调用中断处理函数--》调用驱动的Poll(),此时会禁用网卡的硬中断,有数据来直接写内存启动软中断,硬中断结束返回
分⽚后的⽹络包,就会被送到⽹络接⼝层,在这⾥会通过 ARP 协议获得下⼀跳的 MAC 地址,然后增加帧头和帧 尾,放到发包队列中。
触发软中断告诉⽹卡驱动程序,这⾥有新的⽹络包需要发送,最后驱动程序通过 DMA,从发 包队列中读取⽹络包,将其放⼊到硬件⽹卡的队列中,随后物理⽹卡再将它发送出去。
调用IP层的相应函数将该数据包发送出去
软中断
应⽤层程序调⽤ Socket 接⼝,从内核的 Socket 接收缓冲区读取新到来的数据到应⽤层。
⽹络协议栈从 Socket 发送缓冲区中取出数据包,并按照 TCP/IP 协议栈从上到下逐层处理。
网卡通过DMA将数据包放到指定的内存,地址是网卡驱动分配并且初始化的
在ip层处理最后,会从skb(socket buffer)中得到协议,然后调用对应的协议(TCP或UDP)处理器
协议栈
拷贝数据
传输层
网络层
三种蓝色的缓冲区,都是在内核管理的内存中:环形缓冲区,由于需要 DMA 与网卡交互,理应属于网卡设备驱动的范围。sk_buff 缓冲区,是一个维护网络帧结构的双向链表,链表中的每一个元素都是一个网络帧 (Packet)。虽然 TCP/IP 协议栈分了好几层,但上下不同层之间的传递,实际上只需要操 作这个数据结构中的指针,而无需进行数据复制。套接字缓冲区,则允许应用程序,给每个套接字配置不同大小的接收或发送缓冲区。应用程 序发送数据,实际上就是将数据写入缓冲区;而接收数据,其实就是从缓冲区中读取。
2 硬件中断通知CPU,数据到达网卡硬件中断处理函数
系统调用
驱动
在pool函数中,驱动会一个接一个的读取网卡写到内存中的数据包,内存中数据包的格式只有驱动知道。 驱动程序将内存中的数据包转换成内核网络模块能识别的skb格式,然后调用napi_gro_receive函数
poll()拷贝数据
通过查询路由表确认下⼀跳的 IP,并按照 MTU ⼤⼩进⾏分⽚。
发现目的IP是本地IP,那么会先进行必要的组包(因为IP层负责包拆分为MTU大小)
用户空间
驱动到协议栈
最后数据包交给协议栈处理
struct sk_buff 缓冲区
DMA
socket层发送缓冲区
网络接口层
目的mac地址不是当前网卡,但由于网卡设置了混杂模式而被接收进来会被丢弃,会检查报⽂的合法性,如果不合法则丢弃,合法则会找出该⽹络包的上层 协议的类型,⽐如是 IPv4,还是 IPv6,接着再去掉帧头和帧尾,然后交给⽹络层。
struct sk_buff 缓冲区(backlog queue)
ring buffer环形缓冲区
CPU
硬件部分
然后判断是否开启了RPS,如果开启了,将会调用enqueue_to_backlog在enqueue_to_backlog函数中,会将数据包放入CPU的softnet_data结构体的input_pkt_queue中,然后返回,如果input_pkt_queue满了的话,该数据包将会被丢弃,queue的大小可以通过net.core.netdev_max_backlog来配置
根据四元组「源 IP、源端⼝、⽬的 IP、⽬的端⼝」 作为标识,找出对应的 Socket,并把数据拷⻉到 Socket 的接收缓冲区。
目的IP不是本地IP,且没有开启ip forward功能,那么数据包将被丢弃,如果开启了ip forward功能,那将进入ip_forward函数
为了解决频繁中断带来的性能开销,Linux 内核在 2.6 版本中引⼊了 NAPI 机制,它是混 合「中断和轮询」的⽅式来接收⽹络包,它的核⼼概念就是不采⽤中断的⽅式读取数据,⽽ 是⾸先采⽤中断唤醒数据接收的服务程序,然后 poll 的⽅法来轮询数据。
CPU根据中断表,调用已经注册的中断函数,这个中断函数会调到驱动程序(NIC Driver)中相应的函数poll。驱动先禁用网卡的中断,表示驱动程序已经知道内存中有数据了,告诉网卡下次再收到数据包直接写内存就可以了,不要再通知CPU了,这样可以提高效率,避免CPU不停的被中断。
napi_gro_receive将可以合并的数据包进行合并,这样就只需要调用一次协议栈。
参考的资料
应用层
Socket 层会将应⽤层数据拷⻉到 Socket 发送缓冲区中。
1
socket层接收缓冲区
操作系统内核
网络包packet
内存中提到的 Buffer ,都跟块设备直 接相关;而其他的都是Cache。实际上,sk_buff、套接字缓冲、连接跟踪等,都通过 slab 分配器来管理。你可以直接通过 /proc/slabinfo,来查看它们占用的内存大小。
网卡NIC发送队列
0 条评论
下一页