数据包如何到达应用
(2022-04-15 17:55:23)
应用读取到数据包,分两个过程,一是数据包从网卡到达内核,内核调用协议栈处理放进socket,二是应用如何读取到socket的数据。
第一个过程:
网卡收到数据帧,通过DMA方式将数据帧放入内存的RingBuffer,然后向CPU发起一个硬中断;CPU响应硬中断,调用网卡注册的中断处理函数,该函数几乎没做什么事,
然后发起一个软中断,CPU空闲出去做其它事;内核线程ksoftirqd专门处理软中断,它发现有软中断,调用网卡驱动igb_poll()函数,将数据帧从RingBuffer读出,封装成sk_buff,查看数据帧头部的协议,调用相应协议栈函数(如ip包协议栈注册的函数是ip_rcv函数,arp包是arp_rcv函数);ip_rcv函数处理后再根据ip头部协议(tcp或udp等协议),将ip包送进tcp_rcv函数或udp_rcv函数处理;以以udp_rcv为例,udp_rcv调用__udp4_lib_lookup函数,该函数以包的目标port为索引,寻找哈希桶,再以源地址,源端口,目的地址,目的端口去查找sock。如果找到的哈希桶元素较多,会进行二次hash,无论如何,最终会找到唯一的sock;最后,调用__udp_queue_rcv_skb函数将数据包放到sock的接收数据队列sk_receive_queue中。
第二个过程:
应用程序调用read或recvfrom函数读取数据时,发起系统调用陷入内核;应用程序的socket描述符最终对应到一个socket,socket包含了sock,它里面有协议及对应处理方法,如udp协议对应函数为udp_recvmsg,最后调用到__skb_recv_datagram,它就是读取sk->sk_receive_queue。如果没有数据,允许阻塞,等待数据到来。有数据就从队列读出复制到应用进程。
两篇好帖子:
https://segmentfault.com/a/1190000038374889
https://www.codeleading.com/article/9506996825/
喜欢
0
赠金笔
加载中,请稍候......