一 收包流程- 内核分配一个主内存地址段(DMA缓冲区 RingBuffer),网卡设备可以在DMA缓冲区中读写数据。
- 网卡收到一个数据帧后, 检查MAC地址是否是自己,如果没开启混杂模式,且不是自己就丢了; 如果目的MAC是自己,则将数据帧以DMA方式放入到RingBuffer种,不用cpu参与。
- 当拷贝完成,网卡会触发网卡硬中断,cpu必须立刻响应硬中断, 根据中断类型在中断注册表中 查找对应的中断处理程序(网卡驱动在初始化的时候注册),调用注册的网卡驱动程序收包。 驱动程序收包会为网络帧分配内核数据结构sk_buff,并将它拷贝到sk_buff缓冲区。
- 驱动程序禁止网卡中断,因为已经在处理了,然后网卡驱动程序触发软中断,硬中断返回。
- 内核中的ksoftirqd进程专门处理软中断,收到软中断时候,会调用不同软中断处理,这里会调用 net_recv_action 收包,开始处理包,将sk_buff中的包格式转成上层协议栈能识别的包。
- 协议栈有一系列钩子函数,驱动程序调用现应的协议栈进行包的处理。
- 协议栈在链路层检查报文合法性,找出上层协议类型,去掉帧和帧尾,交给网络层。
- 网络层取出ip,判断网络包是转发,还是本机处理,如果本机处理则取上一层协议类型(TCP、UDP等) 去掉IP头部,交给传输层处理。
- 传输层取出TCP头和UDP头之后,根据四元组标识,找到对应socket,把数据拷贝到socket对应的 缓冲区中,唤醒相关进程收包。
- 至此应用程序通过socket接口,收到数据了。
数据经历: RingBuffer队列---> 拷贝到内核的缓冲区-->应用的内存 二 发包流程- 应用程序调用socket接口, 会把数据放入到socket的缓冲区中。
- 网络协议栈从socket缓冲区中取数据包,按照tcp、udp协议为其增加头部,再增加ip头,并按照数据包总大小和mtu比较,进行ip层的分片,再根据ip层路由 确定下一跳地址。
- 分片后,网络包送到网络接口层,进行物理地址寻址,寻找下一跳的mac地址。
- 然后增加帧头和帧尾,放入到发包队列中。
- 软中断通知驱动程序,发包队列中有数据要发送。
数据经历: 从应用内存---> 拷贝到内核的缓冲区-->RingBuffer队列 【图片来自Linux性能优化实战】
|