对于路由功能模块的学习,也已经很长时间了。关于路由项的创建与查找、策略规则相关的创建与查找、路由缓存的创建与查找,都是分开来分析的,没有说明这些模块是如何配合使用的,以及模块之间的联系。本节就分析一下这几个模块是如何联系在一起的,也作为路由模块学习的小结。
对于协议栈而言,内核中的路由功能模块主要就是提供路由查找功能,而查找功能就集合了策略规则、路由项、路由缓存的查找,而路由功能模块的查找接口对外是统一的。
目前而言,对于输入数据包与输出数据包,路由功能模块提供了两个接口函数,即ip_route_input和ip_route_output_key。下面就分两部分分析一下这两个函数。
1.1 输入路由查找相关的接口
输入路由查找相关的接口有ip_route_input,下面分析一下这个函数。
该函数主要对输入数据包进行路由查找(即netif_receive_skb->ip_rcv->ip_rcv_finish).
对于输入的数据包,会有三个输出结果:
1.本机接收
2.本机转发
3.丢掉数据包
这个函数根据不同的查找结果,会有两个分支:
1.当路由缓存中已存在该数据包对应的路由,则通过查找相应的路由缓存表即可
(rt_hash_table[hash].chain)
2.当路由缓存中不存在该数据包对应的路由时,则通过调用ip_route_input_slow,通过查找路由表,来决定数据包的命运。
这个函数就综合了策略规则的查找、路由项的查找、路由缓存的查找、路由缓存的生成、路由缓存与arp邻居项的绑定。
*/
int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,
u8 tos, struct net_device *dev)
{
struct rtable * rth;
unsigned hash;
int iif = dev->ifindex;
tos &= IPTOS_RT_MASK;
hash = rt_hash(daddr, saddr, iif);
/*加上读锁*/
rcu_read_lock();
/*在hash数组rt_hash_table中,根据hash值找到相应的hash链表,遍历链表中的所用rtable成员
,查找符合条件的路由缓存,若找到的则返回0,并将skb->dst指向该路由缓存。
ip_rcv_finish就会调用skb->dst->input,对数据包进行处理,而在创建路由缓存时,已经将
dst->input的值设置为ip_local_deliver或者ip_forward,根据skb->dst->input函数,就决定了数据包是
发送给本机上层协议进行处理还是转发出去。
*/
for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
rth = rcu_dereference(rth->u.dst.rt_next)) {
if (rth->fl.fl4_dst == daddr &&
rth->fl.fl4_src == saddr &&
rth->fl.iif == iif &&
rth->fl.oif == 0 &&
rth->fl.mark == skb->mark &&
rth->fl.fl4_tos == tos) {
rth->u.dst.lastuse = jiffies;
dst_hold(&rth->u.dst);
rth->u.dst.__use++;
RT_CACHE_STAT_INC(in_hit);
rcu_read_unlock();
skb->dst = (struct dst_entry*)rth;
return 0;
}
RT_CACHE_STAT_INC(in_hlist_search);
}
rcu_read_unlock();
/* Multicast recognition logic is moved from route cache to here.
The problem was that too many Ethernet cards have broken/missing
hardware multicast filters :-( As result the host on multicasting
network acquires a lot of useless route cache entries, sort of
SDR messages from all the world. Now we try to get rid of them.
Really, provided software IP multicast filter is organized
reasonably (at least, hashed), it does not result in a slowdown
comparing with route cache reject entries.
Note, that multicast routers are not affected, because
route cache entry is created eventually.
*/
/*路由缓存没有命中,且目的地址为组播地址时,则进入组播处理流程*/
if (MULTICAST(daddr)) {
struct in_device *in_dev;
rcu_read_lock();
if ((in_dev = __in_dev_get_rcu(dev)) != NULL) {
int our = ip_check_mc(in_dev, daddr, saddr,
skb->nh.iph->protocol);
if (our
#ifdef CONFIG_IP_MROUTE
|| (!LOCAL_MCAST(daddr) && IN_DEV_MFORWARD(in_dev))
#endif
) {
rcu_read_unlock();
return ip_route_input_mc(skb, daddr, saddr,
tos, dev, our);
}
}
rcu_read_unlock();
return -EINVAL;
}
/*当路由缓存查找没有命中,且目的地址不是组播地址时