ip_route_input函数
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;
//根据源地址,目的地址,还有网卡的index来生成哈希值,如果
//是2.4.x的内核,还需要加上tos.
hash = rt_hash(daddr, saddr, iif);
rcu_read_lock();
//通过相应的哈希值,调用rcu_dereference得到RCU保护的临界指针指向一个
//rt_hash_buck中的rtable,进行遍历查找,一直到rtable链表尾部
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;
//找到相匹配的路由信息,将skb->dst赋值为找到的dst_entry,然后
//直接return
}
RT_CACHE_STAT_INC(in_hlist_search);
}
rcu_read_unlock();
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,
ip_hdr(skb)->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;
}
//如果没有查找到相对应的路由信息,就使用这个函数
//进行路由查找,这个函数将调用fib_lookup来查找相对应
//的FIB
return ip_route_input_slow(skb, daddr, saddr, tos, dev);
}
ip_route_input_slow函数
static int ip_route_input_slow(struct sk_buff *skb, __be32
daddr, __be32 saddr,
u8 tos, struct net_device *dev)
{
………………………………………………………..
………………………………………………………..
调用fib_lookup查找路由项目,将结果放在res中
if ((err = fib_lookup(&fl, &res))
!= 0) {
if (!IN_DEV_FORWARD(in_dev))
goto e_hostunreach;
goto no_route;
}
free_res = 1;
RT_CACHE_STAT_INC(in_slow_tot);
//如果是广播路由
if (res.type == RTN_BROADCAST)
goto brd_input;
//如果是本地路由
if (res.type == RTN_LOCAL) {
int result;
//确定来源是否正确,来源不是广播地址或者本地地址
result = fib_validate_source(saddr, daddr, tos,
loopback_dev.ifindex,
dev, &spec_dst, &itag);
if (result < 0)
goto martian_source;
if (result)
flags |= RTCF_DIRECTSRC;
spec_dst = daddr;
goto local_input;
}
//如果当前系统并不处于FORWARD状态
if (!IN_DEV_FORWARD(in_dev))
goto e_hostunreach;
if (res.type != RTN_UNICAST)
goto martian_destination;
//这个函数设置skb->dst->input=ip_forward
err = ip_mkroute_input(skb, &res,
&fl, in_dev, daddr, saddr, tos);
if (err == -ENOBUFS)
goto e_nobufs;
if (err == -EINVAL)
goto e_inval;
done:
in_dev_put(in_dev);
if (free_res)
fib_res_put(&res);
out: return err;
brd_input:
if (skb->protocol != htons(ETH_P_IP))
goto e_inval;
if (ZERONET(saddr))
spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK);
else {
err = fib_validate_source(saddr, 0, tos, 0, dev,
&spec_dst,
&itag);
if (err < 0)
goto martian_source;
if (err)
flags |= RTCF_DIRECTSRC;
}
flags |= RTCF_BROADCAST;
res.type = RTN_BROADCAST;
RT_CACHE_STAT_INC(in_brd);
local_input:
//生成一条新的rtable信息,用于下次路由缓存
rth = dst_alloc(&ipv4_dst_ops);
……………………………………………………………………………………..
……………………………………………………………………………………..
}