diff options
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/addrconf.c | 43 | ||||
-rw-r--r-- | net/ipv6/ip6_fib.c | 25 | ||||
-rw-r--r-- | net/ipv6/ip6mr.c | 5 | ||||
-rw-r--r-- | net/ipv6/ndisc.c | 4 | ||||
-rw-r--r-- | net/ipv6/route.c | 8 |
5 files changed, 45 insertions, 40 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index e7780d72067c..7fd8572bac80 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -813,8 +813,9 @@ static u32 inet6_addr_hash(const struct in6_addr *addr) | |||
813 | /* On success it returns ifp with increased reference count */ | 813 | /* On success it returns ifp with increased reference count */ |
814 | 814 | ||
815 | static struct inet6_ifaddr * | 815 | static struct inet6_ifaddr * |
816 | ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | 816 | ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, |
817 | int scope, u32 flags) | 817 | const struct in6_addr *peer_addr, int pfxlen, |
818 | int scope, u32 flags, u32 valid_lft, u32 prefered_lft) | ||
818 | { | 819 | { |
819 | struct inet6_ifaddr *ifa = NULL; | 820 | struct inet6_ifaddr *ifa = NULL; |
820 | struct rt6_info *rt; | 821 | struct rt6_info *rt; |
@@ -863,6 +864,8 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
863 | } | 864 | } |
864 | 865 | ||
865 | ifa->addr = *addr; | 866 | ifa->addr = *addr; |
867 | if (peer_addr) | ||
868 | ifa->peer_addr = *peer_addr; | ||
866 | 869 | ||
867 | spin_lock_init(&ifa->lock); | 870 | spin_lock_init(&ifa->lock); |
868 | spin_lock_init(&ifa->state_lock); | 871 | spin_lock_init(&ifa->state_lock); |
@@ -872,6 +875,8 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
872 | ifa->scope = scope; | 875 | ifa->scope = scope; |
873 | ifa->prefix_len = pfxlen; | 876 | ifa->prefix_len = pfxlen; |
874 | ifa->flags = flags | IFA_F_TENTATIVE; | 877 | ifa->flags = flags | IFA_F_TENTATIVE; |
878 | ifa->valid_lft = valid_lft; | ||
879 | ifa->prefered_lft = prefered_lft; | ||
875 | ifa->cstamp = ifa->tstamp = jiffies; | 880 | ifa->cstamp = ifa->tstamp = jiffies; |
876 | ifa->tokenized = false; | 881 | ifa->tokenized = false; |
877 | 882 | ||
@@ -1123,8 +1128,9 @@ retry: | |||
1123 | 1128 | ||
1124 | ift = !max_addresses || | 1129 | ift = !max_addresses || |
1125 | ipv6_count_addresses(idev) < max_addresses ? | 1130 | ipv6_count_addresses(idev) < max_addresses ? |
1126 | ipv6_add_addr(idev, &addr, tmp_plen, ipv6_addr_scope(&addr), | 1131 | ipv6_add_addr(idev, &addr, NULL, tmp_plen, |
1127 | addr_flags) : NULL; | 1132 | ipv6_addr_scope(&addr), addr_flags, |
1133 | tmp_valid_lft, tmp_prefered_lft) : NULL; | ||
1128 | if (IS_ERR_OR_NULL(ift)) { | 1134 | if (IS_ERR_OR_NULL(ift)) { |
1129 | in6_ifa_put(ifp); | 1135 | in6_ifa_put(ifp); |
1130 | in6_dev_put(idev); | 1136 | in6_dev_put(idev); |
@@ -1136,8 +1142,6 @@ retry: | |||
1136 | 1142 | ||
1137 | spin_lock_bh(&ift->lock); | 1143 | spin_lock_bh(&ift->lock); |
1138 | ift->ifpub = ifp; | 1144 | ift->ifpub = ifp; |
1139 | ift->valid_lft = tmp_valid_lft; | ||
1140 | ift->prefered_lft = tmp_prefered_lft; | ||
1141 | ift->cstamp = now; | 1145 | ift->cstamp = now; |
1142 | ift->tstamp = tmp_tstamp; | 1146 | ift->tstamp = tmp_tstamp; |
1143 | spin_unlock_bh(&ift->lock); | 1147 | spin_unlock_bh(&ift->lock); |
@@ -2179,16 +2183,19 @@ ok: | |||
2179 | */ | 2183 | */ |
2180 | if (!max_addresses || | 2184 | if (!max_addresses || |
2181 | ipv6_count_addresses(in6_dev) < max_addresses) | 2185 | ipv6_count_addresses(in6_dev) < max_addresses) |
2182 | ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len, | 2186 | ifp = ipv6_add_addr(in6_dev, &addr, NULL, |
2187 | pinfo->prefix_len, | ||
2183 | addr_type&IPV6_ADDR_SCOPE_MASK, | 2188 | addr_type&IPV6_ADDR_SCOPE_MASK, |
2184 | addr_flags); | 2189 | addr_flags, valid_lft, |
2190 | prefered_lft); | ||
2185 | 2191 | ||
2186 | if (IS_ERR_OR_NULL(ifp)) { | 2192 | if (IS_ERR_OR_NULL(ifp)) { |
2187 | in6_dev_put(in6_dev); | 2193 | in6_dev_put(in6_dev); |
2188 | return; | 2194 | return; |
2189 | } | 2195 | } |
2190 | 2196 | ||
2191 | update_lft = create = 1; | 2197 | update_lft = 0; |
2198 | create = 1; | ||
2192 | ifp->cstamp = jiffies; | 2199 | ifp->cstamp = jiffies; |
2193 | ifp->tokenized = tokenized; | 2200 | ifp->tokenized = tokenized; |
2194 | addrconf_dad_start(ifp); | 2201 | addrconf_dad_start(ifp); |
@@ -2209,7 +2216,7 @@ ok: | |||
2209 | stored_lft = ifp->valid_lft - (now - ifp->tstamp) / HZ; | 2216 | stored_lft = ifp->valid_lft - (now - ifp->tstamp) / HZ; |
2210 | else | 2217 | else |
2211 | stored_lft = 0; | 2218 | stored_lft = 0; |
2212 | if (!update_lft && stored_lft) { | 2219 | if (!update_lft && !create && stored_lft) { |
2213 | if (valid_lft > MIN_VALID_LIFETIME || | 2220 | if (valid_lft > MIN_VALID_LIFETIME || |
2214 | valid_lft > stored_lft) | 2221 | valid_lft > stored_lft) |
2215 | update_lft = 1; | 2222 | update_lft = 1; |
@@ -2455,17 +2462,10 @@ static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *p | |||
2455 | prefered_lft = timeout; | 2462 | prefered_lft = timeout; |
2456 | } | 2463 | } |
2457 | 2464 | ||
2458 | ifp = ipv6_add_addr(idev, pfx, plen, scope, ifa_flags); | 2465 | ifp = ipv6_add_addr(idev, pfx, peer_pfx, plen, scope, ifa_flags, |
2466 | valid_lft, prefered_lft); | ||
2459 | 2467 | ||
2460 | if (!IS_ERR(ifp)) { | 2468 | if (!IS_ERR(ifp)) { |
2461 | spin_lock_bh(&ifp->lock); | ||
2462 | ifp->valid_lft = valid_lft; | ||
2463 | ifp->prefered_lft = prefered_lft; | ||
2464 | ifp->tstamp = jiffies; | ||
2465 | if (peer_pfx) | ||
2466 | ifp->peer_addr = *peer_pfx; | ||
2467 | spin_unlock_bh(&ifp->lock); | ||
2468 | |||
2469 | addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, | 2469 | addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, |
2470 | expires, flags); | 2470 | expires, flags); |
2471 | /* | 2471 | /* |
@@ -2557,7 +2557,8 @@ static void add_addr(struct inet6_dev *idev, const struct in6_addr *addr, | |||
2557 | { | 2557 | { |
2558 | struct inet6_ifaddr *ifp; | 2558 | struct inet6_ifaddr *ifp; |
2559 | 2559 | ||
2560 | ifp = ipv6_add_addr(idev, addr, plen, scope, IFA_F_PERMANENT); | 2560 | ifp = ipv6_add_addr(idev, addr, NULL, plen, |
2561 | scope, IFA_F_PERMANENT, 0, 0); | ||
2561 | if (!IS_ERR(ifp)) { | 2562 | if (!IS_ERR(ifp)) { |
2562 | spin_lock_bh(&ifp->lock); | 2563 | spin_lock_bh(&ifp->lock); |
2563 | ifp->flags &= ~IFA_F_TENTATIVE; | 2564 | ifp->flags &= ~IFA_F_TENTATIVE; |
@@ -2683,7 +2684,7 @@ static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr | |||
2683 | #endif | 2684 | #endif |
2684 | 2685 | ||
2685 | 2686 | ||
2686 | ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, addr_flags); | 2687 | ifp = ipv6_add_addr(idev, addr, NULL, 64, IFA_LINK, addr_flags, 0, 0); |
2687 | if (!IS_ERR(ifp)) { | 2688 | if (!IS_ERR(ifp)) { |
2688 | addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0); | 2689 | addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0); |
2689 | addrconf_dad_start(ifp); | 2690 | addrconf_dad_start(ifp); |
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 8b6c77389a04..ed828d6f37b2 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
@@ -1632,27 +1632,28 @@ static int fib6_age(struct rt6_info *rt, void *arg) | |||
1632 | 1632 | ||
1633 | static DEFINE_SPINLOCK(fib6_gc_lock); | 1633 | static DEFINE_SPINLOCK(fib6_gc_lock); |
1634 | 1634 | ||
1635 | void fib6_run_gc(unsigned long expires, struct net *net) | 1635 | void fib6_run_gc(unsigned long expires, struct net *net, bool force) |
1636 | { | 1636 | { |
1637 | if (expires != ~0UL) { | 1637 | unsigned long now; |
1638 | |||
1639 | if (force) { | ||
1638 | spin_lock_bh(&fib6_gc_lock); | 1640 | spin_lock_bh(&fib6_gc_lock); |
1639 | gc_args.timeout = expires ? (int)expires : | 1641 | } else if (!spin_trylock_bh(&fib6_gc_lock)) { |
1640 | net->ipv6.sysctl.ip6_rt_gc_interval; | 1642 | mod_timer(&net->ipv6.ip6_fib_timer, jiffies + HZ); |
1641 | } else { | 1643 | return; |
1642 | if (!spin_trylock_bh(&fib6_gc_lock)) { | ||
1643 | mod_timer(&net->ipv6.ip6_fib_timer, jiffies + HZ); | ||
1644 | return; | ||
1645 | } | ||
1646 | gc_args.timeout = net->ipv6.sysctl.ip6_rt_gc_interval; | ||
1647 | } | 1644 | } |
1645 | gc_args.timeout = expires ? (int)expires : | ||
1646 | net->ipv6.sysctl.ip6_rt_gc_interval; | ||
1648 | 1647 | ||
1649 | gc_args.more = icmp6_dst_gc(); | 1648 | gc_args.more = icmp6_dst_gc(); |
1650 | 1649 | ||
1651 | fib6_clean_all(net, fib6_age, 0, NULL); | 1650 | fib6_clean_all(net, fib6_age, 0, NULL); |
1651 | now = jiffies; | ||
1652 | net->ipv6.ip6_rt_last_gc = now; | ||
1652 | 1653 | ||
1653 | if (gc_args.more) | 1654 | if (gc_args.more) |
1654 | mod_timer(&net->ipv6.ip6_fib_timer, | 1655 | mod_timer(&net->ipv6.ip6_fib_timer, |
1655 | round_jiffies(jiffies | 1656 | round_jiffies(now |
1656 | + net->ipv6.sysctl.ip6_rt_gc_interval)); | 1657 | + net->ipv6.sysctl.ip6_rt_gc_interval)); |
1657 | else | 1658 | else |
1658 | del_timer(&net->ipv6.ip6_fib_timer); | 1659 | del_timer(&net->ipv6.ip6_fib_timer); |
@@ -1661,7 +1662,7 @@ void fib6_run_gc(unsigned long expires, struct net *net) | |||
1661 | 1662 | ||
1662 | static void fib6_gc_timer_cb(unsigned long arg) | 1663 | static void fib6_gc_timer_cb(unsigned long arg) |
1663 | { | 1664 | { |
1664 | fib6_run_gc(0, (struct net *)arg); | 1665 | fib6_run_gc(0, (struct net *)arg, true); |
1665 | } | 1666 | } |
1666 | 1667 | ||
1667 | static int __net_init fib6_net_init(struct net *net) | 1668 | static int __net_init fib6_net_init(struct net *net) |
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 6d78615f6726..a60a84ef04f7 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c | |||
@@ -259,10 +259,12 @@ static void __net_exit ip6mr_rules_exit(struct net *net) | |||
259 | { | 259 | { |
260 | struct mr6_table *mrt, *next; | 260 | struct mr6_table *mrt, *next; |
261 | 261 | ||
262 | rtnl_lock(); | ||
262 | list_for_each_entry_safe(mrt, next, &net->ipv6.mr6_tables, list) { | 263 | list_for_each_entry_safe(mrt, next, &net->ipv6.mr6_tables, list) { |
263 | list_del(&mrt->list); | 264 | list_del(&mrt->list); |
264 | ip6mr_free_table(mrt); | 265 | ip6mr_free_table(mrt); |
265 | } | 266 | } |
267 | rtnl_unlock(); | ||
266 | fib_rules_unregister(net->ipv6.mr6_rules_ops); | 268 | fib_rules_unregister(net->ipv6.mr6_rules_ops); |
267 | } | 269 | } |
268 | #else | 270 | #else |
@@ -289,7 +291,10 @@ static int __net_init ip6mr_rules_init(struct net *net) | |||
289 | 291 | ||
290 | static void __net_exit ip6mr_rules_exit(struct net *net) | 292 | static void __net_exit ip6mr_rules_exit(struct net *net) |
291 | { | 293 | { |
294 | rtnl_lock(); | ||
292 | ip6mr_free_table(net->ipv6.mrt6); | 295 | ip6mr_free_table(net->ipv6.mrt6); |
296 | net->ipv6.mrt6 = NULL; | ||
297 | rtnl_unlock(); | ||
293 | } | 298 | } |
294 | #endif | 299 | #endif |
295 | 300 | ||
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 24c03396e008..79aa9652ed86 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
@@ -1576,7 +1576,7 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, | |||
1576 | switch (event) { | 1576 | switch (event) { |
1577 | case NETDEV_CHANGEADDR: | 1577 | case NETDEV_CHANGEADDR: |
1578 | neigh_changeaddr(&nd_tbl, dev); | 1578 | neigh_changeaddr(&nd_tbl, dev); |
1579 | fib6_run_gc(~0UL, net); | 1579 | fib6_run_gc(0, net, false); |
1580 | idev = in6_dev_get(dev); | 1580 | idev = in6_dev_get(dev); |
1581 | if (!idev) | 1581 | if (!idev) |
1582 | break; | 1582 | break; |
@@ -1586,7 +1586,7 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, | |||
1586 | break; | 1586 | break; |
1587 | case NETDEV_DOWN: | 1587 | case NETDEV_DOWN: |
1588 | neigh_ifdown(&nd_tbl, dev); | 1588 | neigh_ifdown(&nd_tbl, dev); |
1589 | fib6_run_gc(~0UL, net); | 1589 | fib6_run_gc(0, net, false); |
1590 | break; | 1590 | break; |
1591 | case NETDEV_NOTIFY_PEERS: | 1591 | case NETDEV_NOTIFY_PEERS: |
1592 | ndisc_send_unsol_na(dev); | 1592 | ndisc_send_unsol_na(dev); |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index ce9616304521..e22c4db8d07a 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -1310,7 +1310,6 @@ static void icmp6_clean_all(int (*func)(struct rt6_info *rt, void *arg), | |||
1310 | 1310 | ||
1311 | static int ip6_dst_gc(struct dst_ops *ops) | 1311 | static int ip6_dst_gc(struct dst_ops *ops) |
1312 | { | 1312 | { |
1313 | unsigned long now = jiffies; | ||
1314 | struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops); | 1313 | struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops); |
1315 | int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval; | 1314 | int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval; |
1316 | int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size; | 1315 | int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size; |
@@ -1320,13 +1319,12 @@ static int ip6_dst_gc(struct dst_ops *ops) | |||
1320 | int entries; | 1319 | int entries; |
1321 | 1320 | ||
1322 | entries = dst_entries_get_fast(ops); | 1321 | entries = dst_entries_get_fast(ops); |
1323 | if (time_after(rt_last_gc + rt_min_interval, now) && | 1322 | if (time_after(rt_last_gc + rt_min_interval, jiffies) && |
1324 | entries <= rt_max_size) | 1323 | entries <= rt_max_size) |
1325 | goto out; | 1324 | goto out; |
1326 | 1325 | ||
1327 | net->ipv6.ip6_rt_gc_expire++; | 1326 | net->ipv6.ip6_rt_gc_expire++; |
1328 | fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net); | 1327 | fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, entries > rt_max_size); |
1329 | net->ipv6.ip6_rt_last_gc = now; | ||
1330 | entries = dst_entries_get_slow(ops); | 1328 | entries = dst_entries_get_slow(ops); |
1331 | if (entries < ops->gc_thresh) | 1329 | if (entries < ops->gc_thresh) |
1332 | net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1; | 1330 | net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1; |
@@ -2826,7 +2824,7 @@ int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write, | |||
2826 | net = (struct net *)ctl->extra1; | 2824 | net = (struct net *)ctl->extra1; |
2827 | delay = net->ipv6.sysctl.flush_delay; | 2825 | delay = net->ipv6.sysctl.flush_delay; |
2828 | proc_dointvec(ctl, write, buffer, lenp, ppos); | 2826 | proc_dointvec(ctl, write, buffer, lenp, ppos); |
2829 | fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay, net); | 2827 | fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0); |
2830 | return 0; | 2828 | return 0; |
2831 | } | 2829 | } |
2832 | 2830 | ||