您的位置:首页 > 运维架构 > Linux

linux路由内核实现分析(四)---路由缓存机制(4)

2013-07-10 12:32 519 查看
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);

……………………………………………………………………………………..

……………………………………………………………………………………..

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: