Chinaunix首页 | 论坛 | 博客
  • 博客访问: 343549
  • 博文数量: 45
  • 博客积分: 15
  • 博客等级: 民兵
  • 技术积分: 111
  • 用 户 组: 普通用户
  • 注册时间: 2012-01-31 12:31
文章分类

全部博文(45)

文章存档

2015年(2)

2014年(19)

2013年(14)

2012年(10)

我的朋友

分类: LINUX

2013-11-05 15:52:14

声明:本文为原创
#####请转贴时保留以下内容######
作者GTT
本文档归属http://oldtown.cublog.cn/.转载请注明出处!
请提出宝贵意见Mail:mtloveft@hotmail.com
Linux Version:2.6.33
提示:本文是关于Linux实现路由表查找Flow图
 
处理过程如下:
 
 
source file    :    net/ipv4/route.c
method         :    ip_route_input
 
源IP地址如果是multicast,broadcast,loopback地址,意味着数据报不知道从哪来的,只能把数据报废掉了。
目标IP地址如果是braodcast呢?这时有可能是发给自己的啊,所以这时要处理的。源IP可能是0地址么?其实
这种情况在网络中还是经常发生的,比如DHCP的情况。如果Linxu作为DHCP服务器,当然要处理这种情况了。
这时目标IP地址就是广播地址,所以之后的处理就到brd_input。
所以最关键要理解什么时候出现判断条件的情况。如果不是上述的DHCP包,
源IP地址就不能为0地址。所以源,目标判断正确了之后就要进行路由查找了,也就是fib_lookup。根据结果,也就是路由类型进行分歧处理了。
为了再这篇文章里看个究竟,所以把源码贴出来,如下
 

static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
             u8 tos, struct net_device *dev)
{
    struct fib_result res;
    struct in_device *in_dev = in_dev_get(dev);
    struct flowi fl = { .nl_u = { .ip4_u =
                 { .daddr = daddr,
                    .saddr = saddr,
                    .tos = tos,
                    .scope = RT_SCOPE_UNIVERSE,
                 } },
             .mark = skb->mark,
             .iif = dev->ifindex };
    unsigned    flags = 0;
    u32        itag = 0;
    struct rtable * rth;
    unsigned    hash;
    __be32        spec_dst;
    int        err = -EINVAL;
    int        free_res = 0;
    struct net * net = dev_net(dev);

    /* IP on this device is disabled. */

    if (!in_dev)
        goto out;

    /* Check for the most weird martians, which can be not detected
     by fib_lookup.
     */


    if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr) ||
     ipv4_is_loopback(saddr))
        goto martian_source;

    if (daddr == htonl(0xFFFFFFFF) || (saddr == 0 && daddr == 0))
        goto brd_input;

    /* Accept zero addresses only to limited broadcast;
     * I even do not know to fix it or not. Waiting for complains :-)
     */

    if (ipv4_is_zeronet(saddr))
        goto martian_source;

    if (ipv4_is_lbcast(daddr) || ipv4_is_zeronet(daddr) ||
     ipv4_is_loopback(daddr))
        goto martian_destination;

    /*
     *    Now we are ready to route packet.
     */

    if ((err = fib_lookup(net, &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,
                     net->loopback_dev->ifindex,
                     dev, &spec_dst, &itag, skb->mark);
        if (result < 0)
            goto martian_source;
        if (result)
            flags |= RTCF_DIRECTSRC;
        spec_dst = daddr;
        goto local_input;
    }

    if (!IN_DEV_FORWARD(in_dev))
        goto e_hostunreach;
    if (res.type != RTN_UNICAST)
        goto martian_destination;

    err = ip_mkroute_input(skb, &res, &fl, in_dev, daddr, saddr, tos);
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 (ipv4_is_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, skb->mark);
        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:
    rth = dst_alloc(&ipv4_dst_ops);
    if (!rth)
        goto e_nobufs;

    rth->u.dst.output= ip_rt_bug;
    rth->u.dst.obsolete = -1;
    rth->rt_genid = rt_genid(net);

    atomic_set(&rth->u.dst.__refcnt, 1);
    rth->u.dst.flags= DST_HOST;
    if (IN_DEV_CONF_GET(in_dev, NOPOLICY))
        rth->u.dst.flags |= DST_NOPOLICY;
    rth->fl.fl4_dst    = daddr;
    rth->rt_dst    = daddr;
    rth->fl.fl4_tos    = tos;
    rth->fl.mark = skb->mark;
    rth->fl.fl4_src    = saddr;
    rth->rt_src    = saddr;
#ifdef CONFIG_NET_CLS_ROUTE
    rth->u.dst.tclassid = itag;
#endif
    rth->rt_iif    =
    rth->fl.iif    = dev->ifindex;
    rth->u.dst.dev    = net->loopback_dev;
    dev_hold(rth->u.dst.dev);
    rth->idev    = in_dev_get(rth->u.dst.dev);
    rth->rt_gateway    = daddr;
    rth->rt_spec_dst= spec_dst;
    rth->u.dst.input= ip_local_deliver;
    rth->rt_flags     = flags|RTCF_LOCAL;
    if (res.type == RTN_UNREACHABLE) {
        rth->u.dst.input= ip_error;
        rth->u.dst.error= -err;
        rth->rt_flags     &= ~RTCF_LOCAL;
    }
    rth->rt_type    = res.type;
    hash = rt_hash(daddr, saddr, fl.iif, rt_genid(net));
    err = rt_intern_hash(hash, rth, NULL, skb, fl.iif);
    goto done;

no_route:
    RT_CACHE_STAT_INC(in_no_route);
    spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE);
    res.type = RTN_UNREACHABLE;
    if (err == -ESRCH)
        err = -ENETUNREACH;
    goto local_input;

    /*
     *    Do not cache martian addresses: they should be logged (RFC1812)
     */

martian_destination:
    RT_CACHE_STAT_INC(in_martian_dst);
#ifdef CONFIG_IP_ROUTE_VERBOSE
    if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit())
        printk(KERN_WARNING "martian destination %pI4 from %pI4, dev %s\n",
            &daddr, &saddr, dev->name);
#endif

e_hostunreach:
    err = -EHOSTUNREACH;
    goto done;

e_inval:
    err = -EINVAL;
    goto done;

e_nobufs:
    err = -ENOBUFS;
    goto done;

martian_source:
    ip_handle_martian_source(dev, in_dev, skb, daddr, saddr);
    goto e_inval;
}


源码还是比较长的,要有耐心读下去啊!
其实struct flowi这个结构还是比较有技巧的。
阅读(2099) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~