内核阅读之浅析Linux2.6.34内核路由数据转发(二)
Linux路由相关函数数据跟踪浅析
1.int ip_rcv()函数 该函数在Linux2.6.34\net\ipv4\Ip_input.c
该函数是在L2调用deliver_skb()是调用的,当然它的数据包类型ptype=ETH_P_IP。这里主要是对收上来的数据包进行一些验证其合法性,然后就交给了ip_rcv_finish()函数继续处理。
2.ip_rcv_finish()函数 Ip_rcv_finish()在Linux2.6.34\net\ipv4\Ip_input.c
Ip_rcv_finish()函数是之后所有函数的归属函数,因为最后的最后还是要返回这个函数来调用dst_input()函数来继续调用ip_local_deliver()或ip_forward()。该函数主要是调用了ip_route_input()函数来对IP数据包进行路由查找和设置路由信息。Ip_route_input()函数在Linux2.6.34\net\ipv4\Route.c
该函数主要就干了三件事,刚开始是在缓存cash里查找相应的路由项,如果有找到,则更改skb的目标地址(IP地址),即为下一跳的地址(IP地址),然后返回执行相应的input函数。若在缓存cash中找不到,则判断IP数据包的目标地址是不是多播地址,若是,则按照多播协议规则将其转发,这只关注单播的情况,所以这里不加以说明。若是单播地址,而且在缓存cash中也找不到相应的路由项,则会调用ip_route_input_slow()函数,该函数在Linux2.6.34\net\ipv4\Route.c
这个函数还是比较复杂的,因为它对整个路由信息查找过程考虑的很周到,不会落下如何可能存在的情况。那它主要干了些什么呢?主要是查找路由表,获得路由表结果信息,通过该结果信息进行判断执行。通过路由结果信息的ret.type进行判断,如果是为广播,则按照广播协议规则转发,这里不详细阐述。如果是本机的IP数据包,将input=ip_local_deliver(),紧接着会将当前IP数据包的一些路由信息更新到路由哈希表中,然后改变skb的地址(IP地址),也就是本机的IP地址,然后返回到ip_rcv_finish()调用input,其实就是ip_local_deliver()函数。Ip_local_deliver()函数在Linux2.6.34\net\ipv4\Ip_input.c
如果skb是数据碎片,则会等待其它的skb来了组成完整的数据包才会调用ip_local_deliver_finish()提交给L4。这样L3分发本机skb数据跟踪就结束了。
紧接着ip_route_input_slow()函数的分析,若IP数据包既不是广播数据包,也不是本机包,那就是单一地址的forward包啦!ip_route_input_slow()会很自觉的调用ip_mkroute_input()函数来完成IP数据包的forward。Ip_mkroute_input()函数在Linux2.6.34\net\ipv4\route.c
该函数主要还是先调用_mkroute_input()函数来做些forward的前期数据准备。__mkroute_input()函数在Linux2.6.34\net\ipv4\route.c
这个函数主要是获取skb的路由信息,用来更新路由哈希表。可以清楚的看到该函数将input=ip_forward()、output=ip_output()。到了这里函数会一路返回到ip_rcv_finish()函数调用input,其实就是ip_forward()函数。
Ip_forward()函数在Linux2.6.34\net\ipv4\ip_forward.c
该函数主要还是对数据包进行检测和改变一些结构变量。最后调用ip_forward_finish()来继续完成IP数据包的转发。
Ip_forward_finish()函数在Linux2.6.34\net\ipv4\ip_forward.c
哈哈,这里终于看到output啦,根据上面的设置,是ip_output()函数。
Ip_output()函数在Linux2.6.34\net\ipv4\ip_output.c
该函数继续调用ip_finish_output()函数来完成IP数据包的转发。
Ip_finish_output()函数在Linux2.6.34\net\ipv4\ip_output.c
在这个函数里,会对数据包进行检查,查看数据包的长度是否大于MTU的长度,如果大于MTU的长度,则会调用ip_fragment()函数对数据包进行拆分,然后调用再调用ip_finish_output2()函数;否则直接调用ip_finish_output2()函数。
Ip_finish_output2()函数在Linux2.6.34\net\ipv4\ip_output.c
Ip_finish_output2()函数会将skb送到neighboring subsystem,这个子系统会经过ARP协议获得L3地址(IP地址)对应的L2的地址(MAC地址)。这样整个L3单播地址路由skb数据跟踪就结束了。
若有错误之处,欢迎指正学习!