文章目录
网络层的数据包发送过程应该分两个层次来看:
- 网络层提供了哪些接口给高层协议(tcp、udp等)使用;
- 网络层内部在收到要发送的数据包后做了哪些处理,然后是如何将数据包发给设备接口层的;
高层协议先通过网络层提供的发送接口将要发送的数据准备好,添加自己的首部后,将数据包交给网络层继续发送出去。
高层协议发送接口
网络层对外提供了较多的发送接口,高层协议会根据场景使用,下面对常用的接口进行简要的介绍。
ip_queue_xmit()
int ip_queue_xmit(struct sk_buff *skb, int ipfragok);
该接口主要由tcp使用。
ip_build_and_send_pkt()
待补充…
ip_send_reply()
待补充…
ip_append_data()
该接口主要由udp使用。它并非真正的发送接口,高层协议可以连续多次调用该函数将要发送的数据封装成一个IP报文(可能包含多个片段),然后通过ip_push_pending_frames()发送给网络层。
该接口在封装skb的时候,充分考虑了IP层的分段,其实现非常的复杂,但是它对高效的组织skb数据相当有参考意义。该接口的实现参考笔记IPv4之数据包发送接口ip_append_data(一)和IPv4之数据包发送接口ip_append_data(二)。
ip_push_pending_frames()
配合ip_append_data(),将前者封装好的skb添加IP包头后交给网络层继续处理。为了完整性,该函数的分析见IPv4之数据包发送接口ip_append_data(二)。
IP内部数据包发送流程
上面的发送接口处理完毕后,最终都会调用ip_local_out()继续发送报文。
ip_local_out()
int ip_local_out(struct sk_buff *skb)
{
int err;
err = __ip_local_out(skb);
// 如果Netfilter不处理该数据包就会返回1,交给路由结果处理,
// 对于本地生成的数据包,对应的函数是ip_output()
if (likely(err == 1))
err = dst_output(skb);
return err;
}
int __ip_local_out(struct sk_buff *skb)
{
struct