应用程序从recvmsg()返回,获得数据包内容和精确的接收时间戳,可以进行后续的业务逻辑处理。
内核响应系统调用,将Socket接收缓冲区中的数据拷贝到用户提供的buffer中,并将存储的硬件/软件时间戳通过控制消息(cmsg)拷贝给应用程序。
应用程序调用recvmsg()系统调用来读取数据。使用recvmsg()是因为它能同时接收数据和“控制消息”(ancillary data)。
根据IP和端口号,内核找到匹配的Socket,并将数据包放入该Socket的接收缓冲区(sk_receive_queue)。时间戳作为元数据与数据包一同存储。
包含时间戳的sk_buff被传递给netif_receive_skb()或gro_receive(),进入通用网络协议栈。它会依次经过L2(链路层), L3(IP层), L4(TCP/UDP层)的处理。
在软中断上下文(NET_RX_SOFTIRQ)中,驱动的poll函数被调用。它从Ring
Buffer中取出数据包,为其创建一个核心数据结构sk_buff。
CPU响应中断,执行简短的驱动中断处理程序。它会禁用中断并调度NAPI(软中断),将耗时的工作延迟处理。
数据写入完成后,NIC向CPU发起一个硬件中断,通知有新数据到达。
NIC通过DMA引擎将数据包内容和附带的硬件时间戳写入内核预先分配的内存区域(Ring Buffer)。
NIC的PHY/MAC层解析信号,识别出以太网帧的边界 (如SFD: Start Frame Delimiter)。
网卡从物理介质(如网线、光纤)接收到电信号或光信号。
__netif_receive_skb_core函数)。sk_buff之后,即将递交给上层协议栈之前。ktime_get_real()获取当前系统时钟,并将其记录在sk_buff的特定字段中。