路由3 【ip_route_input函数分析(2) 】
1 继续读ip_route_input_slow函数 2 /* 3 * NOTE. We drop all the packets that has local source 4 * addresses, because every properly looped back packet 5 * must have correct destination already attached by output routine. 6 * 我们丢弃所有从127.0.0.1发来的包 7 * 8 * Such approach solves two big problems: 9 * 1. Not simplex devices are handled properly. 10 * 合理解决多设备的问题 11 * 2. IP spoofing attempts are filtered with 100% of guarantee. 12 * 百分百过滤IP spoofing尝试 13 */ 14 15 static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, 16 u8 tos, struct net_device *dev) 17 { 18 struct fib_result res; 19 struct in_device *in_dev = in_dev_get(dev); 20 struct flowi fl = { .nl_u = { .ip4_u = 21 { .daddr = daddr, 22 .saddr = saddr, 23 .tos = tos, 24 .scope = RT_SCOPE_UNIVERSE, 25 } }, 26 .mark = skb->mark, 27 .iif = dev->ifindex }; 28 unsigned flags = 0; 29 u32 itag = 0; 30 struct rtable * rth; 31 unsigned hash; 32 __be32 spec_dst; 33 int err = -EINVAL; 34 int free_res = 0; 35 struct net * net = dev_net(dev); 36 37 /* IP on this device is disabled. */ 38 39 if (!in_dev) 40 goto out; 41 42 /* Check for the most weird martians, which can be not detected 43 by fib_lookup. 44 */ 45 46 if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr) || 47 ipv4_is_loopback(saddr)) 48 goto martian_source; 49 50 if (daddr == htonl(0xFFFFFFFF) || (saddr == 0 && daddr == 0)) 51 goto brd_input; 52 53 /* Accept zero addresses only to limited broadcast; 54 * I even do not know to fix it or not. Waiting for complains :-) 55 */ 56 if (ipv4_is_zeronet(saddr)) 57 goto martian_source; 58 59 if (ipv4_is_lbcast(daddr) || ipv4_is_zeronet(daddr) || 60 ipv4_is_loopback(daddr)) 61 goto martian_destination; 62 63 /* 64 * 前面都是通过检查包的源和目的地址的合理性来确定对不同包的处理 65 * Now we are ready to route packet. 66 */ 67 if ((err = fib_lookup(net, &fl, &res)) != 0) { /*查找路由*/ 68 if (!IN_DEV_FORWARD(in_dev)) /*没找到,先判断转发标志是否打开*/ 69 goto e_hostunreach; 70 goto no_route; 71 } 72 /*z找到路由的标志*/ 73 free_res = 1; 74 75 RT_CACHE_STAT_INC(in_slow_tot); 76 77 /*根据查找到的路由类型,分类处理*/ 78 if (res.type == RTN_BROADCAST) 79 goto brd_input; 80 81 if (res.type == RTN_LOCAL) { 82 int result; 83 /*如果是发给本机的包,则验证原地址是否合法*/ 84 result = fib_validate_source(saddr, daddr, tos, 85 net->loopback_dev->ifindex, 86 dev, &spec_dst, &itag, skb->mark); 87 if (result < 0) 88 goto martian_source; 89 if (result) 90 flags |= RTCF_DIRECTSRC; 91 spec_dst = daddr; 92 goto local_input; 93 } 94 95 if (!IN_DEV_FORWARD(in_dev)) 96 goto e_hostunreach; 97 if (res.type != RTN_UNICAST) 98 goto martian_destination; 99 100 /*当查到的路由类型是指向远端的主机,把此路由加入cache中*/ 101 err = ip_mkroute_input(skb, &res, &fl, in_dev, daddr, saddr, tos); 102 done: 103 in_dev_put(in_dev); 104 if (free_res) 105 fib_res_put(&res); 106 out: return err; 107 108 /*当目的地址是广播地址,或查到的路由类型是广播类型*/ 109 brd_input: 110 if (skb->protocol != htons(ETH_P_IP)) 111 goto e_inval; 112 113 if (ipv4_is_zeronet(saddr)) 114 spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK); 115 else { 116 err = fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst, 117 &itag, skb->mark); 118 if (err < 0) 119 goto martian_source; 120 if (err) 121 flags |= RTCF_DIRECTSRC; 122 } 123 flags |= RTCF_BROADCAST; 124 res.type = RTN_BROADCAST; 125 RT_CACHE_STAT_INC(in_brd); 126 127 /*当查找到的路由指向本机时*/ 128 local_input: 129 /*分配缓存路由项空间,并以确定的spec_dest等信息给路由项赋值*/ 130 rth = dst_alloc(&ipv4_dst_ops); 131 if (!rth) 132 goto e_nobufs; 133 134 rth->u.dst.output= ip_rt_bug; 135 rth->u.dst.obsolete = -1; 136 rth->rt_genid = rt_genid(net); 137 138 atomic_set(&rth->u.dst.__refcnt, 1); 139 rth->u.dst.flags= DST_HOST; 140 if (IN_DEV_CONF_GET(in_dev, NOPOLICY)) 141 rth->u.dst.flags |= DST_NOPOLICY; 142 rth->fl.fl4_dst = daddr; 143 rth->rt_dst = daddr; 144 rth->fl.fl4_tos = tos; 145 rth->fl.mark = skb->mark; 146 rth->fl.fl4_src = saddr; 147 rth->rt_src = saddr; 148 #ifdef CONFIG_NET_CLS_ROUTE 149 rth->u.dst.tclassid = itag; 150 #endif 151 rth->rt_iif = 152 rth->fl.iif = dev->ifindex; 153 rth->u.dst.dev = net->loopback_dev; 154 dev_hold(rth->u.dst.dev); 155 rth->idev = in_dev_get(rth->u.dst.dev); 156 rth->rt_gateway = daddr; 157 rth->rt_spec_dst= spec_dst; 158 rth->u.dst.input= ip_local_deliver; /*路由查找结束后会调用此函数把报文送给上层处理*/ 159 rth->rt_flags = flags|RTCF_LOCAL; 160 if (res.type == RTN_UNREACHABLE) { 161 rth->u.dst.input= ip_error; 162 rth->u.dst.error= -err; 163 rth->rt_flags &= ~RTCF_LOCAL; 164 } 165 rth->rt_type = res.type; 166 hash = rt_hash(daddr, saddr, fl.iif, rt_genid(net)); 167 err = rt_intern_hash(hash, rth, NULL, skb, fl.iif); /*想缓存中插入新的路由项*/ 168 goto done; 169 170 /*没有查找到路由的时候,向缓存中添加一条不可达路由项*/ 171 no_route: 172 RT_CACHE_STAT_INC(in_no_route); 173 spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE); 174 res.type = RTN_UNREACHABLE; 175 if (err == -ESRCH) 176 err = -ENETUNREACH; 177 goto local_input; 178 179 /* 180 * Do not cache martian addresses: they should be logged (RFC1812) 181 */ 182 martian_destination: 183 RT_CACHE_STAT_INC(in_martian_dst); 184 #ifdef CONFIG_IP_ROUTE_VERBOSE 185 if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) 186 printk(KERN_WARNING "martian destination %pI4 from %pI4, dev %s\n", 187 &daddr, &saddr, dev->name); 188 #endif 189 190 e_hostunreach: 191 err = -EHOSTUNREACH; 192 goto done; 193 194 e_inval: 195 err = -EINVAL; 196 goto done; 197 198 e_nobufs: 199 err = -ENOBUFS; 200 goto done; 201 202 martian_source: 203 ip_handle_martian_source(dev, in_dev, skb, daddr, saddr); 204 goto e_inval; 205 } 206 207 以上函数都是从ip_route_input函数开始,所调用到的部分函数。当网卡收到报文到达IP层后,IP层先作路由查询以便决定把它送到哪。而根据源与目的地址以及其他方面的检测,路由分了多播路由,广播路由,单播路由,还有本地路由。这些路由在cache中的生存策略也是不同的。一个绝对重点的函数赋值就是rth->u.dst.input,最后函数在IP层的分发就是通过这个函数实现。