路由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
",
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层的分发就是通过这个函数实现。
原文地址:https://www.cnblogs.com/listenerln/p/6846328.html