linux 发送报文过程简析
Linux 网络栈可以处理 L2 层以上的报文,网络报文向外发送需要经由对应的网络设备驱动完成。
用户进程通过调用 write 等函数构造报文,根据报文类型,通过 tcp_sendmsg() 、udp_sendmsg()生成相应的传输层报文,然后不通格式的类型的报文进行相应的处理后,通过 ip_route_out() 查找路由,最后都交给 ip_output() 函数处理,构造网络层报文,并进行相应处理,最终交由 dev_queue_xmit() 函数处理,提交给对应的网络设备驱动提供的函数接口,向外部发送报文。
下面是 Linux 内核网络的数据流图:
重要数据结构 —— sk_buff
sk_buff 是 Linux 网络代码中最重要的数据结构,代表已经接受或正要传输的数据的报头。由巨大的变量堆(heap)组成。
许多层次的网络(MAC、IP、TCP或UDP)都会使用这个结构,当该结构从一个分层传到另一个分层时,不同字段发生变化,如从 L3 传给 L2 需要附加报头。这需要在缓冲区开端新增空间,Linux 内核提供了 skb_reverse 函数执行该操作。
重要函数 —— ip_output()
报文的向外发送和转发最终都经过 ip_output 函数,其中使用 ip_finish_output 对报文进行处理,包括分片、ARP学习、MAC地址修改或填充等。
<