A-A+
路由表查找过程(ip_route_input_slow)
Linux Version:2.6.33
提示:本文是关于Linux实现路由表查找Flow图!
处理过程如下:
source file:net/ipv4/route.c
method:ip_route_input
L3 IPv4 处理流程:http://blog.chinaunix.net/u3/114767/showart_2272778.html
源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_genidrt_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这个结构还是比较有技巧的。