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

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);

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

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

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值