- 论坛徽章:
- 0
|
内核版本:2.6.32
fib_validate_source这个函数为什么会查询两次路由表呢,个人觉得第二次查询好像没有什么必要啊?
毕竟和第一次查询的区别仅仅在于设置了输出接口而已,求高人指点。
223 /* Given (packet source, input interface) and optional (dst, oif, tos):
224 - (main) check, that source is valid i.e. not broadcast or our local
225 address.
226 - figure out what "logical" interface this packet arrived
227 and calculate "specific destination" address.
228 - check, that packet arrived from expected physical interface.
229 */
230
231 int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
232 struct net_device *dev, __be32 *spec_dst,
233 u32 *itag, u32 mark)
234 {
235 struct in_device *in_dev;
236 struct flowi fl = { .nl_u = { .ip4_u =
237 { .daddr = src,
238 .saddr = dst,
239 .tos = tos } },
240 .mark = mark,
241 .iif = oif };
242
243 struct fib_result res;
244 int no_addr, rpf;
245 int ret;
246 struct net *net;
247
248 no_addr = rpf = 0;
249 rcu_read_lock();
250 in_dev = __in_dev_get_rcu(dev);
251 if (in_dev) {
252 no_addr = in_dev->ifa_list == NULL;
253 rpf = IN_DEV_RPFILTER(in_dev);
254 if (mark && !IN_DEV_SRC_VMARK(in_dev))
255 fl.mark = 0;
256 }
257 rcu_read_unlock();
258
259 if (in_dev == NULL)
260 goto e_inval;
261
262 net = dev_net(dev);
263 if (fib_lookup(net, &fl, &res))
264 goto last_resort;
265 if (res.type != RTN_UNICAST)
266 goto e_inval_res;
267 *spec_dst = FIB_RES_PREFSRC(res);
268 fib_combine_itag(itag, &res);
269 #ifdef CONFIG_IP_ROUTE_MULTIPATH
270 if (FIB_RES_DEV(res) == dev || res.fi->fib_nhs > 1)
271 #else
272 if (FIB_RES_DEV(res) == dev)
273 #endif
274 {
275 ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
276 fib_res_put(&res);
277 return ret;
278 }
279 fib_res_put(&res);
280 if (no_addr)
281 goto last_resort;
282 if (rpf == 1)
283 goto e_inval;
284 fl.oif = dev->ifindex;
285
286 ret = 0;
287 if (fib_lookup(net, &fl, &res) == 0) {
288 if (res.type == RTN_UNICAST) {
289 *spec_dst = FIB_RES_PREFSRC(res);
290 ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
291 }
292 fib_res_put(&res);
293 }
294 return ret;
295
296 last_resort:
297 if (rpf)
298 goto e_inval;
299 *spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE);
300 *itag = 0;
301 return 0;
302
303 e_inval_res:
304 fib_res_put(&res);
305 e_inval:
306 return -EINVAL;
307 } |
|