aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/route.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2011-04-28 17:48:42 -0400
committerDavid S. Miller <davem@davemloft.net>2011-04-29 01:26:00 -0400
commit813b3b5db831ddbd92b5ce0fdeb74e3368f1323c (patch)
tree636c404ea6f255c0b8793af4e83f9df19d61c94f /net/ipv4/route.c
parentcf91166223772ef4a2ed98b9874958bf6a2470df (diff)
ipv4: Use caller's on-stack flowi as-is in output route lookups.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/route.c')
-rw-r--r--net/ipv4/route.c158
1 files changed, 80 insertions, 78 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index fb9211adf079..93f71be1d5d1 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1767,7 +1767,7 @@ static unsigned int ipv4_default_mtu(const struct dst_entry *dst)
1767 return mtu; 1767 return mtu;
1768} 1768}
1769 1769
1770static void rt_init_metrics(struct rtable *rt, const struct flowi4 *oldflp4, 1770static void rt_init_metrics(struct rtable *rt, const struct flowi4 *fl4,
1771 struct fib_info *fi) 1771 struct fib_info *fi)
1772{ 1772{
1773 struct inet_peer *peer; 1773 struct inet_peer *peer;
@@ -1776,7 +1776,7 @@ static void rt_init_metrics(struct rtable *rt, const struct flowi4 *oldflp4,
1776 /* If a peer entry exists for this destination, we must hook 1776 /* If a peer entry exists for this destination, we must hook
1777 * it up in order to get at cached metrics. 1777 * it up in order to get at cached metrics.
1778 */ 1778 */
1779 if (oldflp4 && (oldflp4->flowi4_flags & FLOWI_FLAG_PRECOW_METRICS)) 1779 if (fl4 && (fl4->flowi4_flags & FLOWI_FLAG_PRECOW_METRICS))
1780 create = 1; 1780 create = 1;
1781 1781
1782 rt->peer = peer = inet_getpeer_v4(rt->rt_dst, create); 1782 rt->peer = peer = inet_getpeer_v4(rt->rt_dst, create);
@@ -1803,7 +1803,7 @@ static void rt_init_metrics(struct rtable *rt, const struct flowi4 *oldflp4,
1803 } 1803 }
1804} 1804}
1805 1805
1806static void rt_set_nexthop(struct rtable *rt, const struct flowi4 *oldflp4, 1806static void rt_set_nexthop(struct rtable *rt, const struct flowi4 *fl4,
1807 const struct fib_result *res, 1807 const struct fib_result *res,
1808 struct fib_info *fi, u16 type, u32 itag) 1808 struct fib_info *fi, u16 type, u32 itag)
1809{ 1809{
@@ -1813,7 +1813,7 @@ static void rt_set_nexthop(struct rtable *rt, const struct flowi4 *oldflp4,
1813 if (FIB_RES_GW(*res) && 1813 if (FIB_RES_GW(*res) &&
1814 FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) 1814 FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
1815 rt->rt_gateway = FIB_RES_GW(*res); 1815 rt->rt_gateway = FIB_RES_GW(*res);
1816 rt_init_metrics(rt, oldflp4, fi); 1816 rt_init_metrics(rt, fl4, fi);
1817#ifdef CONFIG_IP_ROUTE_CLASSID 1817#ifdef CONFIG_IP_ROUTE_CLASSID
1818 dst->tclassid = FIB_RES_NH(*res).nh_tclassid; 1818 dst->tclassid = FIB_RES_NH(*res).nh_tclassid;
1819#endif 1819#endif
@@ -2354,12 +2354,12 @@ EXPORT_SYMBOL(ip_route_input_common);
2354/* called with rcu_read_lock() */ 2354/* called with rcu_read_lock() */
2355static struct rtable *__mkroute_output(const struct fib_result *res, 2355static struct rtable *__mkroute_output(const struct fib_result *res,
2356 const struct flowi4 *fl4, 2356 const struct flowi4 *fl4,
2357 const struct flowi4 *oldflp4, 2357 __be32 orig_daddr, __be32 orig_saddr,
2358 struct net_device *dev_out, 2358 int orig_oif, struct net_device *dev_out,
2359 unsigned int flags) 2359 unsigned int flags)
2360{ 2360{
2361 struct fib_info *fi = res->fi; 2361 struct fib_info *fi = res->fi;
2362 u32 tos = RT_FL_TOS(oldflp4); 2362 u32 tos = RT_FL_TOS(fl4);
2363 struct in_device *in_dev; 2363 struct in_device *in_dev;
2364 u16 type = res->type; 2364 u16 type = res->type;
2365 struct rtable *rth; 2365 struct rtable *rth;
@@ -2386,8 +2386,8 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
2386 fi = NULL; 2386 fi = NULL;
2387 } else if (type == RTN_MULTICAST) { 2387 } else if (type == RTN_MULTICAST) {
2388 flags |= RTCF_MULTICAST | RTCF_LOCAL; 2388 flags |= RTCF_MULTICAST | RTCF_LOCAL;
2389 if (!ip_check_mc_rcu(in_dev, oldflp4->daddr, oldflp4->saddr, 2389 if (!ip_check_mc_rcu(in_dev, fl4->daddr, fl4->saddr,
2390 oldflp4->flowi4_proto)) 2390 fl4->flowi4_proto))
2391 flags &= ~RTCF_LOCAL; 2391 flags &= ~RTCF_LOCAL;
2392 /* If multicast route do not exist use 2392 /* If multicast route do not exist use
2393 * default one, but do not gateway in this case. 2393 * default one, but do not gateway in this case.
@@ -2405,8 +2405,8 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
2405 2405
2406 rth->dst.output = ip_output; 2406 rth->dst.output = ip_output;
2407 2407
2408 rth->rt_key_dst = oldflp4->daddr; 2408 rth->rt_key_dst = orig_daddr;
2409 rth->rt_key_src = oldflp4->saddr; 2409 rth->rt_key_src = orig_saddr;
2410 rth->rt_genid = rt_genid(dev_net(dev_out)); 2410 rth->rt_genid = rt_genid(dev_net(dev_out));
2411 rth->rt_flags = flags; 2411 rth->rt_flags = flags;
2412 rth->rt_type = type; 2412 rth->rt_type = type;
@@ -2414,9 +2414,9 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
2414 rth->rt_dst = fl4->daddr; 2414 rth->rt_dst = fl4->daddr;
2415 rth->rt_src = fl4->saddr; 2415 rth->rt_src = fl4->saddr;
2416 rth->rt_route_iif = 0; 2416 rth->rt_route_iif = 0;
2417 rth->rt_iif = oldflp4->flowi4_oif ? : dev_out->ifindex; 2417 rth->rt_iif = orig_oif ? : dev_out->ifindex;
2418 rth->rt_oif = oldflp4->flowi4_oif; 2418 rth->rt_oif = orig_oif;
2419 rth->rt_mark = oldflp4->flowi4_mark; 2419 rth->rt_mark = fl4->flowi4_mark;
2420 rth->rt_gateway = fl4->daddr; 2420 rth->rt_gateway = fl4->daddr;
2421 rth->rt_spec_dst= fl4->saddr; 2421 rth->rt_spec_dst= fl4->saddr;
2422 rth->rt_peer_genid = 0; 2422 rth->rt_peer_genid = 0;
@@ -2439,7 +2439,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
2439#ifdef CONFIG_IP_MROUTE 2439#ifdef CONFIG_IP_MROUTE
2440 if (type == RTN_MULTICAST) { 2440 if (type == RTN_MULTICAST) {
2441 if (IN_DEV_MFORWARD(in_dev) && 2441 if (IN_DEV_MFORWARD(in_dev) &&
2442 !ipv4_is_local_multicast(oldflp4->daddr)) { 2442 !ipv4_is_local_multicast(fl4->daddr)) {
2443 rth->dst.input = ip_mr_input; 2443 rth->dst.input = ip_mr_input;
2444 rth->dst.output = ip_mc_output; 2444 rth->dst.output = ip_mc_output;
2445 } 2445 }
@@ -2447,7 +2447,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
2447#endif 2447#endif
2448 } 2448 }
2449 2449
2450 rt_set_nexthop(rth, oldflp4, res, fi, type, 0); 2450 rt_set_nexthop(rth, fl4, res, fi, type, 0);
2451 2451
2452 return rth; 2452 return rth;
2453} 2453}
@@ -2457,36 +2457,37 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
2457 * called with rcu_read_lock(); 2457 * called with rcu_read_lock();
2458 */ 2458 */
2459 2459
2460static struct rtable *ip_route_output_slow(struct net *net, 2460static struct rtable *ip_route_output_slow(struct net *net, struct flowi4 *fl4)
2461 const struct flowi4 *oldflp4)
2462{ 2461{
2463 u32 tos = RT_FL_TOS(oldflp4);
2464 struct flowi4 fl4;
2465 struct fib_result res;
2466 unsigned int flags = 0;
2467 struct net_device *dev_out = NULL; 2462 struct net_device *dev_out = NULL;
2463 u32 tos = RT_FL_TOS(fl4);
2464 unsigned int flags = 0;
2465 struct fib_result res;
2468 struct rtable *rth; 2466 struct rtable *rth;
2467 __be32 orig_daddr;
2468 __be32 orig_saddr;
2469 int orig_oif;
2469 2470
2470 res.fi = NULL; 2471 res.fi = NULL;
2471#ifdef CONFIG_IP_MULTIPLE_TABLES 2472#ifdef CONFIG_IP_MULTIPLE_TABLES
2472 res.r = NULL; 2473 res.r = NULL;
2473#endif 2474#endif
2474 2475
2475 fl4.flowi4_oif = oldflp4->flowi4_oif; 2476 orig_daddr = fl4->daddr;
2476 fl4.flowi4_iif = net->loopback_dev->ifindex; 2477 orig_saddr = fl4->saddr;
2477 fl4.flowi4_mark = oldflp4->flowi4_mark; 2478 orig_oif = fl4->flowi4_oif;
2478 fl4.daddr = oldflp4->daddr; 2479
2479 fl4.saddr = oldflp4->saddr; 2480 fl4->flowi4_iif = net->loopback_dev->ifindex;
2480 fl4.flowi4_tos = tos & IPTOS_RT_MASK; 2481 fl4->flowi4_tos = tos & IPTOS_RT_MASK;
2481 fl4.flowi4_scope = ((tos & RTO_ONLINK) ? 2482 fl4->flowi4_scope = ((tos & RTO_ONLINK) ?
2482 RT_SCOPE_LINK : RT_SCOPE_UNIVERSE); 2483 RT_SCOPE_LINK : RT_SCOPE_UNIVERSE);
2483 2484
2484 rcu_read_lock(); 2485 rcu_read_lock();
2485 if (oldflp4->saddr) { 2486 if (fl4->saddr) {
2486 rth = ERR_PTR(-EINVAL); 2487 rth = ERR_PTR(-EINVAL);
2487 if (ipv4_is_multicast(oldflp4->saddr) || 2488 if (ipv4_is_multicast(fl4->saddr) ||
2488 ipv4_is_lbcast(oldflp4->saddr) || 2489 ipv4_is_lbcast(fl4->saddr) ||
2489 ipv4_is_zeronet(oldflp4->saddr)) 2490 ipv4_is_zeronet(fl4->saddr))
2490 goto out; 2491 goto out;
2491 2492
2492 /* I removed check for oif == dev_out->oif here. 2493 /* I removed check for oif == dev_out->oif here.
@@ -2497,11 +2498,11 @@ static struct rtable *ip_route_output_slow(struct net *net,
2497 of another iface. --ANK 2498 of another iface. --ANK
2498 */ 2499 */
2499 2500
2500 if (oldflp4->flowi4_oif == 0 && 2501 if (fl4->flowi4_oif == 0 &&
2501 (ipv4_is_multicast(oldflp4->daddr) || 2502 (ipv4_is_multicast(fl4->daddr) ||
2502 ipv4_is_lbcast(oldflp4->daddr))) { 2503 ipv4_is_lbcast(fl4->daddr))) {
2503 /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */ 2504 /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */
2504 dev_out = __ip_dev_find(net, oldflp4->saddr, false); 2505 dev_out = __ip_dev_find(net, fl4->saddr, false);
2505 if (dev_out == NULL) 2506 if (dev_out == NULL)
2506 goto out; 2507 goto out;
2507 2508
@@ -2520,20 +2521,20 @@ static struct rtable *ip_route_output_slow(struct net *net,
2520 Luckily, this hack is good workaround. 2521 Luckily, this hack is good workaround.
2521 */ 2522 */
2522 2523
2523 fl4.flowi4_oif = dev_out->ifindex; 2524 fl4->flowi4_oif = dev_out->ifindex;
2524 goto make_route; 2525 goto make_route;
2525 } 2526 }
2526 2527
2527 if (!(oldflp4->flowi4_flags & FLOWI_FLAG_ANYSRC)) { 2528 if (!(fl4->flowi4_flags & FLOWI_FLAG_ANYSRC)) {
2528 /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */ 2529 /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */
2529 if (!__ip_dev_find(net, oldflp4->saddr, false)) 2530 if (!__ip_dev_find(net, fl4->saddr, false))
2530 goto out; 2531 goto out;
2531 } 2532 }
2532 } 2533 }
2533 2534
2534 2535
2535 if (oldflp4->flowi4_oif) { 2536 if (fl4->flowi4_oif) {
2536 dev_out = dev_get_by_index_rcu(net, oldflp4->flowi4_oif); 2537 dev_out = dev_get_by_index_rcu(net, fl4->flowi4_oif);
2537 rth = ERR_PTR(-ENODEV); 2538 rth = ERR_PTR(-ENODEV);
2538 if (dev_out == NULL) 2539 if (dev_out == NULL)
2539 goto out; 2540 goto out;
@@ -2543,37 +2544,37 @@ static struct rtable *ip_route_output_slow(struct net *net,
2543 rth = ERR_PTR(-ENETUNREACH); 2544 rth = ERR_PTR(-ENETUNREACH);
2544 goto out; 2545 goto out;
2545 } 2546 }
2546 if (ipv4_is_local_multicast(oldflp4->daddr) || 2547 if (ipv4_is_local_multicast(fl4->daddr) ||
2547 ipv4_is_lbcast(oldflp4->daddr)) { 2548 ipv4_is_lbcast(fl4->daddr)) {
2548 if (!fl4.saddr) 2549 if (!fl4->saddr)
2549 fl4.saddr = inet_select_addr(dev_out, 0, 2550 fl4->saddr = inet_select_addr(dev_out, 0,
2550 RT_SCOPE_LINK); 2551 RT_SCOPE_LINK);
2551 goto make_route; 2552 goto make_route;
2552 } 2553 }
2553 if (!fl4.saddr) { 2554 if (fl4->saddr) {
2554 if (ipv4_is_multicast(oldflp4->daddr)) 2555 if (ipv4_is_multicast(fl4->daddr))
2555 fl4.saddr = inet_select_addr(dev_out, 0, 2556 fl4->saddr = inet_select_addr(dev_out, 0,
2556 fl4.flowi4_scope); 2557 fl4->flowi4_scope);
2557 else if (!oldflp4->daddr) 2558 else if (!fl4->daddr)
2558 fl4.saddr = inet_select_addr(dev_out, 0, 2559 fl4->saddr = inet_select_addr(dev_out, 0,
2559 RT_SCOPE_HOST); 2560 RT_SCOPE_HOST);
2560 } 2561 }
2561 } 2562 }
2562 2563
2563 if (!fl4.daddr) { 2564 if (!fl4->daddr) {
2564 fl4.daddr = fl4.saddr; 2565 fl4->daddr = fl4->saddr;
2565 if (!fl4.daddr) 2566 if (!fl4->daddr)
2566 fl4.daddr = fl4.saddr = htonl(INADDR_LOOPBACK); 2567 fl4->daddr = fl4->saddr = htonl(INADDR_LOOPBACK);
2567 dev_out = net->loopback_dev; 2568 dev_out = net->loopback_dev;
2568 fl4.flowi4_oif = net->loopback_dev->ifindex; 2569 fl4->flowi4_oif = net->loopback_dev->ifindex;
2569 res.type = RTN_LOCAL; 2570 res.type = RTN_LOCAL;
2570 flags |= RTCF_LOCAL; 2571 flags |= RTCF_LOCAL;
2571 goto make_route; 2572 goto make_route;
2572 } 2573 }
2573 2574
2574 if (fib_lookup(net, &fl4, &res)) { 2575 if (fib_lookup(net, fl4, &res)) {
2575 res.fi = NULL; 2576 res.fi = NULL;
2576 if (oldflp4->flowi4_oif) { 2577 if (fl4->flowi4_oif) {
2577 /* Apparently, routing tables are wrong. Assume, 2578 /* Apparently, routing tables are wrong. Assume,
2578 that the destination is on link. 2579 that the destination is on link.
2579 2580
@@ -2592,9 +2593,9 @@ static struct rtable *ip_route_output_slow(struct net *net,
2592 likely IPv6, but we do not. 2593 likely IPv6, but we do not.
2593 */ 2594 */
2594 2595
2595 if (fl4.saddr == 0) 2596 if (fl4->saddr == 0)
2596 fl4.saddr = inet_select_addr(dev_out, 0, 2597 fl4->saddr = inet_select_addr(dev_out, 0,
2597 RT_SCOPE_LINK); 2598 RT_SCOPE_LINK);
2598 res.type = RTN_UNICAST; 2599 res.type = RTN_UNICAST;
2599 goto make_route; 2600 goto make_route;
2600 } 2601 }
@@ -2603,44 +2604,45 @@ static struct rtable *ip_route_output_slow(struct net *net,
2603 } 2604 }
2604 2605
2605 if (res.type == RTN_LOCAL) { 2606 if (res.type == RTN_LOCAL) {
2606 if (!fl4.saddr) { 2607 if (!fl4->saddr) {
2607 if (res.fi->fib_prefsrc) 2608 if (res.fi->fib_prefsrc)
2608 fl4.saddr = res.fi->fib_prefsrc; 2609 fl4->saddr = res.fi->fib_prefsrc;
2609 else 2610 else
2610 fl4.saddr = fl4.daddr; 2611 fl4->saddr = fl4->daddr;
2611 } 2612 }
2612 dev_out = net->loopback_dev; 2613 dev_out = net->loopback_dev;
2613 fl4.flowi4_oif = dev_out->ifindex; 2614 fl4->flowi4_oif = dev_out->ifindex;
2614 res.fi = NULL; 2615 res.fi = NULL;
2615 flags |= RTCF_LOCAL; 2616 flags |= RTCF_LOCAL;
2616 goto make_route; 2617 goto make_route;
2617 } 2618 }
2618 2619
2619#ifdef CONFIG_IP_ROUTE_MULTIPATH 2620#ifdef CONFIG_IP_ROUTE_MULTIPATH
2620 if (res.fi->fib_nhs > 1 && fl4.flowi4_oif == 0) 2621 if (res.fi->fib_nhs > 1 && fl4->flowi4_oif == 0)
2621 fib_select_multipath(&res); 2622 fib_select_multipath(&res);
2622 else 2623 else
2623#endif 2624#endif
2624 if (!res.prefixlen && 2625 if (!res.prefixlen &&
2625 res.table->tb_num_default > 1 && 2626 res.table->tb_num_default > 1 &&
2626 res.type == RTN_UNICAST && !fl4.flowi4_oif) 2627 res.type == RTN_UNICAST && !fl4->flowi4_oif)
2627 fib_select_default(&res); 2628 fib_select_default(&res);
2628 2629
2629 if (!fl4.saddr) 2630 if (!fl4->saddr)
2630 fl4.saddr = FIB_RES_PREFSRC(net, res); 2631 fl4->saddr = FIB_RES_PREFSRC(net, res);
2631 2632
2632 dev_out = FIB_RES_DEV(res); 2633 dev_out = FIB_RES_DEV(res);
2633 fl4.flowi4_oif = dev_out->ifindex; 2634 fl4->flowi4_oif = dev_out->ifindex;
2634 2635
2635 2636
2636make_route: 2637make_route:
2637 rth = __mkroute_output(&res, &fl4, oldflp4, dev_out, flags); 2638 rth = __mkroute_output(&res, fl4, orig_daddr, orig_saddr, orig_oif,
2639 dev_out, flags);
2638 if (!IS_ERR(rth)) { 2640 if (!IS_ERR(rth)) {
2639 unsigned int hash; 2641 unsigned int hash;
2640 2642
2641 hash = rt_hash(oldflp4->daddr, oldflp4->saddr, oldflp4->flowi4_oif, 2643 hash = rt_hash(orig_daddr, orig_saddr, orig_oif,
2642 rt_genid(dev_net(dev_out))); 2644 rt_genid(dev_net(dev_out)));
2643 rth = rt_intern_hash(hash, rth, NULL, oldflp4->flowi4_oif); 2645 rth = rt_intern_hash(hash, rth, NULL, orig_oif);
2644 } 2646 }
2645 2647
2646out: 2648out:
@@ -2648,7 +2650,7 @@ out:
2648 return rth; 2650 return rth;
2649} 2651}
2650 2652
2651struct rtable *__ip_route_output_key(struct net *net, const struct flowi4 *flp4) 2653struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *flp4)
2652{ 2654{
2653 struct rtable *rth; 2655 struct rtable *rth;
2654 unsigned int hash; 2656 unsigned int hash;