diff options
Diffstat (limited to 'net/ipv6/route.c')
| -rw-r--r-- | net/ipv6/route.c | 58 |
1 files changed, 34 insertions, 24 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 23a20d62daac..7a014ca877ed 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
| @@ -111,8 +111,8 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, | |||
| 111 | int iif, int type, u32 portid, u32 seq, | 111 | int iif, int type, u32 portid, u32 seq, |
| 112 | unsigned int flags); | 112 | unsigned int flags); |
| 113 | static struct rt6_info *rt6_find_cached_rt(const struct fib6_result *res, | 113 | static struct rt6_info *rt6_find_cached_rt(const struct fib6_result *res, |
| 114 | struct in6_addr *daddr, | 114 | const struct in6_addr *daddr, |
| 115 | struct in6_addr *saddr); | 115 | const struct in6_addr *saddr); |
| 116 | 116 | ||
| 117 | #ifdef CONFIG_IPV6_ROUTE_INFO | 117 | #ifdef CONFIG_IPV6_ROUTE_INFO |
| 118 | static struct fib6_info *rt6_add_route_info(struct net *net, | 118 | static struct fib6_info *rt6_add_route_info(struct net *net, |
| @@ -1295,6 +1295,13 @@ static struct rt6_info *rt6_make_pcpu_route(struct net *net, | |||
| 1295 | prev = cmpxchg(p, NULL, pcpu_rt); | 1295 | prev = cmpxchg(p, NULL, pcpu_rt); |
| 1296 | BUG_ON(prev); | 1296 | BUG_ON(prev); |
| 1297 | 1297 | ||
| 1298 | if (res->f6i->fib6_destroying) { | ||
| 1299 | struct fib6_info *from; | ||
| 1300 | |||
| 1301 | from = xchg((__force struct fib6_info **)&pcpu_rt->from, NULL); | ||
| 1302 | fib6_info_release(from); | ||
| 1303 | } | ||
| 1304 | |||
| 1298 | return pcpu_rt; | 1305 | return pcpu_rt; |
| 1299 | } | 1306 | } |
| 1300 | 1307 | ||
| @@ -1566,31 +1573,44 @@ out: | |||
| 1566 | * Caller has to hold rcu_read_lock() | 1573 | * Caller has to hold rcu_read_lock() |
| 1567 | */ | 1574 | */ |
| 1568 | static struct rt6_info *rt6_find_cached_rt(const struct fib6_result *res, | 1575 | static struct rt6_info *rt6_find_cached_rt(const struct fib6_result *res, |
| 1569 | struct in6_addr *daddr, | 1576 | const struct in6_addr *daddr, |
| 1570 | struct in6_addr *saddr) | 1577 | const struct in6_addr *saddr) |
| 1571 | { | 1578 | { |
| 1579 | const struct in6_addr *src_key = NULL; | ||
| 1572 | struct rt6_exception_bucket *bucket; | 1580 | struct rt6_exception_bucket *bucket; |
| 1573 | struct in6_addr *src_key = NULL; | ||
| 1574 | struct rt6_exception *rt6_ex; | 1581 | struct rt6_exception *rt6_ex; |
| 1575 | struct rt6_info *ret = NULL; | 1582 | struct rt6_info *ret = NULL; |
| 1576 | 1583 | ||
| 1577 | bucket = rcu_dereference(res->f6i->rt6i_exception_bucket); | ||
| 1578 | |||
| 1579 | #ifdef CONFIG_IPV6_SUBTREES | 1584 | #ifdef CONFIG_IPV6_SUBTREES |
| 1580 | /* fib6i_src.plen != 0 indicates f6i is in subtree | 1585 | /* fib6i_src.plen != 0 indicates f6i is in subtree |
| 1581 | * and exception table is indexed by a hash of | 1586 | * and exception table is indexed by a hash of |
| 1582 | * both fib6_dst and fib6_src. | 1587 | * both fib6_dst and fib6_src. |
| 1583 | * Otherwise, the exception table is indexed by | 1588 | * However, the src addr used to create the hash |
| 1584 | * a hash of only fib6_dst. | 1589 | * might not be exactly the passed in saddr which |
| 1590 | * is a /128 addr from the flow. | ||
| 1591 | * So we need to use f6i->fib6_src to redo lookup | ||
| 1592 | * if the passed in saddr does not find anything. | ||
| 1593 | * (See the logic in ip6_rt_cache_alloc() on how | ||
| 1594 | * rt->rt6i_src is updated.) | ||
| 1585 | */ | 1595 | */ |
| 1586 | if (res->f6i->fib6_src.plen) | 1596 | if (res->f6i->fib6_src.plen) |
| 1587 | src_key = saddr; | 1597 | src_key = saddr; |
| 1598 | find_ex: | ||
| 1588 | #endif | 1599 | #endif |
| 1600 | bucket = rcu_dereference(res->f6i->rt6i_exception_bucket); | ||
| 1589 | rt6_ex = __rt6_find_exception_rcu(&bucket, daddr, src_key); | 1601 | rt6_ex = __rt6_find_exception_rcu(&bucket, daddr, src_key); |
| 1590 | 1602 | ||
| 1591 | if (rt6_ex && !rt6_check_expired(rt6_ex->rt6i)) | 1603 | if (rt6_ex && !rt6_check_expired(rt6_ex->rt6i)) |
| 1592 | ret = rt6_ex->rt6i; | 1604 | ret = rt6_ex->rt6i; |
| 1593 | 1605 | ||
| 1606 | #ifdef CONFIG_IPV6_SUBTREES | ||
| 1607 | /* Use fib6_src as src_key and redo lookup */ | ||
| 1608 | if (!ret && src_key && src_key != &res->f6i->fib6_src.addr) { | ||
| 1609 | src_key = &res->f6i->fib6_src.addr; | ||
| 1610 | goto find_ex; | ||
| 1611 | } | ||
| 1612 | #endif | ||
| 1613 | |||
| 1594 | return ret; | 1614 | return ret; |
| 1595 | } | 1615 | } |
| 1596 | 1616 | ||
| @@ -2665,12 +2685,10 @@ u32 ip6_mtu_from_fib6(const struct fib6_result *res, | |||
| 2665 | const struct in6_addr *daddr, | 2685 | const struct in6_addr *daddr, |
| 2666 | const struct in6_addr *saddr) | 2686 | const struct in6_addr *saddr) |
| 2667 | { | 2687 | { |
| 2668 | struct rt6_exception_bucket *bucket; | ||
| 2669 | const struct fib6_nh *nh = res->nh; | 2688 | const struct fib6_nh *nh = res->nh; |
| 2670 | struct fib6_info *f6i = res->f6i; | 2689 | struct fib6_info *f6i = res->f6i; |
| 2671 | const struct in6_addr *src_key; | ||
| 2672 | struct rt6_exception *rt6_ex; | ||
| 2673 | struct inet6_dev *idev; | 2690 | struct inet6_dev *idev; |
| 2691 | struct rt6_info *rt; | ||
| 2674 | u32 mtu = 0; | 2692 | u32 mtu = 0; |
| 2675 | 2693 | ||
| 2676 | if (unlikely(fib6_metric_locked(f6i, RTAX_MTU))) { | 2694 | if (unlikely(fib6_metric_locked(f6i, RTAX_MTU))) { |
| @@ -2679,18 +2697,10 @@ u32 ip6_mtu_from_fib6(const struct fib6_result *res, | |||
| 2679 | goto out; | 2697 | goto out; |
| 2680 | } | 2698 | } |
| 2681 | 2699 | ||
| 2682 | src_key = NULL; | 2700 | rt = rt6_find_cached_rt(res, daddr, saddr); |
| 2683 | #ifdef CONFIG_IPV6_SUBTREES | 2701 | if (unlikely(rt)) { |
| 2684 | if (f6i->fib6_src.plen) | 2702 | mtu = dst_metric_raw(&rt->dst, RTAX_MTU); |
| 2685 | src_key = saddr; | 2703 | } else { |
| 2686 | #endif | ||
| 2687 | |||
| 2688 | bucket = rcu_dereference(f6i->rt6i_exception_bucket); | ||
| 2689 | rt6_ex = __rt6_find_exception_rcu(&bucket, daddr, src_key); | ||
| 2690 | if (rt6_ex && !rt6_check_expired(rt6_ex->rt6i)) | ||
| 2691 | mtu = dst_metric_raw(&rt6_ex->rt6i->dst, RTAX_MTU); | ||
| 2692 | |||
| 2693 | if (likely(!mtu)) { | ||
| 2694 | struct net_device *dev = nh->fib_nh_dev; | 2704 | struct net_device *dev = nh->fib_nh_dev; |
| 2695 | 2705 | ||
| 2696 | mtu = IPV6_MIN_MTU; | 2706 | mtu = IPV6_MIN_MTU; |
