aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/addrconf.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2010-03-05 15:46:18 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2010-03-05 15:46:18 -0500
commit3fa04ecd72780da31ba8b329e148179bc24a9c7d (patch)
treef5d462fd4aee086952d18f159f737c450ab46b3b /net/ipv6/addrconf.c
parent180b62a3d837613fcac3ce89576526423926c3c3 (diff)
parent1cda707d52e51a6cafac0aef12d2bd7052d572e6 (diff)
Merge branch 'writeback-for-2.6.34' into nfs-for-2.6.34
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r--net/ipv6/addrconf.c110
1 files changed, 67 insertions, 43 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index de7a194a64ab..88fd8c5877ee 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -278,31 +278,31 @@ static void addrconf_mod_timer(struct inet6_ifaddr *ifp,
278 278
279static int snmp6_alloc_dev(struct inet6_dev *idev) 279static int snmp6_alloc_dev(struct inet6_dev *idev)
280{ 280{
281 if (snmp_mib_init((void **)idev->stats.ipv6, 281 if (snmp_mib_init((void __percpu **)idev->stats.ipv6,
282 sizeof(struct ipstats_mib)) < 0) 282 sizeof(struct ipstats_mib)) < 0)
283 goto err_ip; 283 goto err_ip;
284 if (snmp_mib_init((void **)idev->stats.icmpv6, 284 if (snmp_mib_init((void __percpu **)idev->stats.icmpv6,
285 sizeof(struct icmpv6_mib)) < 0) 285 sizeof(struct icmpv6_mib)) < 0)
286 goto err_icmp; 286 goto err_icmp;
287 if (snmp_mib_init((void **)idev->stats.icmpv6msg, 287 if (snmp_mib_init((void __percpu **)idev->stats.icmpv6msg,
288 sizeof(struct icmpv6msg_mib)) < 0) 288 sizeof(struct icmpv6msg_mib)) < 0)
289 goto err_icmpmsg; 289 goto err_icmpmsg;
290 290
291 return 0; 291 return 0;
292 292
293err_icmpmsg: 293err_icmpmsg:
294 snmp_mib_free((void **)idev->stats.icmpv6); 294 snmp_mib_free((void __percpu **)idev->stats.icmpv6);
295err_icmp: 295err_icmp:
296 snmp_mib_free((void **)idev->stats.ipv6); 296 snmp_mib_free((void __percpu **)idev->stats.ipv6);
297err_ip: 297err_ip:
298 return -ENOMEM; 298 return -ENOMEM;
299} 299}
300 300
301static void snmp6_free_dev(struct inet6_dev *idev) 301static void snmp6_free_dev(struct inet6_dev *idev)
302{ 302{
303 snmp_mib_free((void **)idev->stats.icmpv6msg); 303 snmp_mib_free((void __percpu **)idev->stats.icmpv6msg);
304 snmp_mib_free((void **)idev->stats.icmpv6); 304 snmp_mib_free((void __percpu **)idev->stats.icmpv6);
305 snmp_mib_free((void **)idev->stats.ipv6); 305 snmp_mib_free((void __percpu **)idev->stats.ipv6);
306} 306}
307 307
308/* Nobody refers to this device, we may destroy it. */ 308/* Nobody refers to this device, we may destroy it. */
@@ -502,8 +502,11 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old)
502 if (p == &net->ipv6.devconf_dflt->forwarding) 502 if (p == &net->ipv6.devconf_dflt->forwarding)
503 return 0; 503 return 0;
504 504
505 if (!rtnl_trylock()) 505 if (!rtnl_trylock()) {
506 /* Restore the original values before restarting */
507 *p = old;
506 return restart_syscall(); 508 return restart_syscall();
509 }
507 510
508 if (p == &net->ipv6.devconf_all->forwarding) { 511 if (p == &net->ipv6.devconf_all->forwarding) {
509 __s32 newf = net->ipv6.devconf_all->forwarding; 512 __s32 newf = net->ipv6.devconf_all->forwarding;
@@ -989,8 +992,7 @@ struct ipv6_saddr_dst {
989 992
990static inline int ipv6_saddr_preferred(int type) 993static inline int ipv6_saddr_preferred(int type)
991{ 994{
992 if (type & (IPV6_ADDR_MAPPED|IPV6_ADDR_COMPATv4| 995 if (type & (IPV6_ADDR_MAPPED|IPV6_ADDR_COMPATv4|IPV6_ADDR_LOOPBACK))
993 IPV6_ADDR_LOOPBACK|IPV6_ADDR_RESERVED))
994 return 1; 996 return 1;
995 return 0; 997 return 0;
996} 998}
@@ -2646,7 +2648,8 @@ static int addrconf_ifdown(struct net_device *dev, int how)
2646 2648
2647 write_lock_bh(&addrconf_hash_lock); 2649 write_lock_bh(&addrconf_hash_lock);
2648 while ((ifa = *bifa) != NULL) { 2650 while ((ifa = *bifa) != NULL) {
2649 if (ifa->idev == idev) { 2651 if (ifa->idev == idev &&
2652 (how || !(ifa->flags&IFA_F_PERMANENT))) {
2650 *bifa = ifa->lst_next; 2653 *bifa = ifa->lst_next;
2651 ifa->lst_next = NULL; 2654 ifa->lst_next = NULL;
2652 addrconf_del_timer(ifa); 2655 addrconf_del_timer(ifa);
@@ -2686,18 +2689,30 @@ static int addrconf_ifdown(struct net_device *dev, int how)
2686 write_lock_bh(&idev->lock); 2689 write_lock_bh(&idev->lock);
2687 } 2690 }
2688#endif 2691#endif
2689 while ((ifa = idev->addr_list) != NULL) { 2692 bifa = &idev->addr_list;
2690 idev->addr_list = ifa->if_next; 2693 while ((ifa = *bifa) != NULL) {
2691 ifa->if_next = NULL; 2694 if (how == 0 && (ifa->flags&IFA_F_PERMANENT)) {
2692 ifa->dead = 1; 2695 /* Retain permanent address on admin down */
2693 addrconf_del_timer(ifa); 2696 bifa = &ifa->if_next;
2694 write_unlock_bh(&idev->lock); 2697
2698 /* Restart DAD if needed when link comes back up */
2699 if ( !((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) ||
2700 idev->cnf.accept_dad <= 0 ||
2701 (ifa->flags & IFA_F_NODAD)))
2702 ifa->flags |= IFA_F_TENTATIVE;
2703 } else {
2704 *bifa = ifa->if_next;
2705 ifa->if_next = NULL;
2695 2706
2696 __ipv6_ifa_notify(RTM_DELADDR, ifa); 2707 ifa->dead = 1;
2697 atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa); 2708 write_unlock_bh(&idev->lock);
2698 in6_ifa_put(ifa);
2699 2709
2700 write_lock_bh(&idev->lock); 2710 __ipv6_ifa_notify(RTM_DELADDR, ifa);
2711 atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
2712 in6_ifa_put(ifa);
2713
2714 write_lock_bh(&idev->lock);
2715 }
2701 } 2716 }
2702 write_unlock_bh(&idev->lock); 2717 write_unlock_bh(&idev->lock);
2703 2718
@@ -2789,14 +2804,14 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
2789 read_lock_bh(&idev->lock); 2804 read_lock_bh(&idev->lock);
2790 if (ifp->dead) 2805 if (ifp->dead)
2791 goto out; 2806 goto out;
2792 spin_lock_bh(&ifp->lock);
2793 2807
2808 spin_lock(&ifp->lock);
2794 if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || 2809 if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
2795 idev->cnf.accept_dad < 1 || 2810 idev->cnf.accept_dad < 1 ||
2796 !(ifp->flags&IFA_F_TENTATIVE) || 2811 !(ifp->flags&IFA_F_TENTATIVE) ||
2797 ifp->flags & IFA_F_NODAD) { 2812 ifp->flags & IFA_F_NODAD) {
2798 ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); 2813 ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED);
2799 spin_unlock_bh(&ifp->lock); 2814 spin_unlock(&ifp->lock);
2800 read_unlock_bh(&idev->lock); 2815 read_unlock_bh(&idev->lock);
2801 2816
2802 addrconf_dad_completed(ifp); 2817 addrconf_dad_completed(ifp);
@@ -2804,7 +2819,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
2804 } 2819 }
2805 2820
2806 if (!(idev->if_flags & IF_READY)) { 2821 if (!(idev->if_flags & IF_READY)) {
2807 spin_unlock_bh(&ifp->lock); 2822 spin_unlock(&ifp->lock);
2808 read_unlock_bh(&idev->lock); 2823 read_unlock_bh(&idev->lock);
2809 /* 2824 /*
2810 * If the device is not ready: 2825 * If the device is not ready:
@@ -2824,7 +2839,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
2824 ip6_ins_rt(ifp->rt); 2839 ip6_ins_rt(ifp->rt);
2825 2840
2826 addrconf_dad_kick(ifp); 2841 addrconf_dad_kick(ifp);
2827 spin_unlock_bh(&ifp->lock); 2842 spin_unlock(&ifp->lock);
2828out: 2843out:
2829 read_unlock_bh(&idev->lock); 2844 read_unlock_bh(&idev->lock);
2830} 2845}
@@ -2840,14 +2855,15 @@ static void addrconf_dad_timer(unsigned long data)
2840 read_unlock_bh(&idev->lock); 2855 read_unlock_bh(&idev->lock);
2841 goto out; 2856 goto out;
2842 } 2857 }
2843 spin_lock_bh(&ifp->lock); 2858
2859 spin_lock(&ifp->lock);
2844 if (ifp->probes == 0) { 2860 if (ifp->probes == 0) {
2845 /* 2861 /*
2846 * DAD was successful 2862 * DAD was successful
2847 */ 2863 */
2848 2864
2849 ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); 2865 ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED);
2850 spin_unlock_bh(&ifp->lock); 2866 spin_unlock(&ifp->lock);
2851 read_unlock_bh(&idev->lock); 2867 read_unlock_bh(&idev->lock);
2852 2868
2853 addrconf_dad_completed(ifp); 2869 addrconf_dad_completed(ifp);
@@ -2857,7 +2873,7 @@ static void addrconf_dad_timer(unsigned long data)
2857 2873
2858 ifp->probes--; 2874 ifp->probes--;
2859 addrconf_mod_timer(ifp, AC_DAD, ifp->idev->nd_parms->retrans_time); 2875 addrconf_mod_timer(ifp, AC_DAD, ifp->idev->nd_parms->retrans_time);
2860 spin_unlock_bh(&ifp->lock); 2876 spin_unlock(&ifp->lock);
2861 read_unlock_bh(&idev->lock); 2877 read_unlock_bh(&idev->lock);
2862 2878
2863 /* send a neighbour solicitation for our addr */ 2879 /* send a neighbour solicitation for our addr */
@@ -2905,12 +2921,12 @@ static void addrconf_dad_run(struct inet6_dev *idev) {
2905 2921
2906 read_lock_bh(&idev->lock); 2922 read_lock_bh(&idev->lock);
2907 for (ifp = idev->addr_list; ifp; ifp = ifp->if_next) { 2923 for (ifp = idev->addr_list; ifp; ifp = ifp->if_next) {
2908 spin_lock_bh(&ifp->lock); 2924 spin_lock(&ifp->lock);
2909 if (!(ifp->flags & IFA_F_TENTATIVE)) { 2925 if (!(ifp->flags & IFA_F_TENTATIVE)) {
2910 spin_unlock_bh(&ifp->lock); 2926 spin_unlock(&ifp->lock);
2911 continue; 2927 continue;
2912 } 2928 }
2913 spin_unlock_bh(&ifp->lock); 2929 spin_unlock(&ifp->lock);
2914 addrconf_dad_kick(ifp); 2930 addrconf_dad_kick(ifp);
2915 } 2931 }
2916 read_unlock_bh(&idev->lock); 2932 read_unlock_bh(&idev->lock);
@@ -3027,14 +3043,14 @@ static const struct file_operations if6_fops = {
3027 .release = seq_release_net, 3043 .release = seq_release_net,
3028}; 3044};
3029 3045
3030static int if6_proc_net_init(struct net *net) 3046static int __net_init if6_proc_net_init(struct net *net)
3031{ 3047{
3032 if (!proc_net_fops_create(net, "if_inet6", S_IRUGO, &if6_fops)) 3048 if (!proc_net_fops_create(net, "if_inet6", S_IRUGO, &if6_fops))
3033 return -ENOMEM; 3049 return -ENOMEM;
3034 return 0; 3050 return 0;
3035} 3051}
3036 3052
3037static void if6_proc_net_exit(struct net *net) 3053static void __net_exit if6_proc_net_exit(struct net *net)
3038{ 3054{
3039 proc_net_remove(net, "if_inet6"); 3055 proc_net_remove(net, "if_inet6");
3040} 3056}
@@ -3752,8 +3768,8 @@ static inline size_t inet6_if_nlmsg_size(void)
3752 ); 3768 );
3753} 3769}
3754 3770
3755static inline void __snmp6_fill_stats(u64 *stats, void **mib, int items, 3771static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib,
3756 int bytes) 3772 int items, int bytes)
3757{ 3773{
3758 int i; 3774 int i;
3759 int pad = bytes - sizeof(u64) * items; 3775 int pad = bytes - sizeof(u64) * items;
@@ -3772,10 +3788,10 @@ static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype,
3772{ 3788{
3773 switch(attrtype) { 3789 switch(attrtype) {
3774 case IFLA_INET6_STATS: 3790 case IFLA_INET6_STATS:
3775 __snmp6_fill_stats(stats, (void **)idev->stats.ipv6, IPSTATS_MIB_MAX, bytes); 3791 __snmp6_fill_stats(stats, (void __percpu **)idev->stats.ipv6, IPSTATS_MIB_MAX, bytes);
3776 break; 3792 break;
3777 case IFLA_INET6_ICMP6STATS: 3793 case IFLA_INET6_ICMP6STATS:
3778 __snmp6_fill_stats(stats, (void **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes); 3794 __snmp6_fill_stats(stats, (void __percpu **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes);
3779 break; 3795 break;
3780 } 3796 }
3781} 3797}
@@ -4028,12 +4044,15 @@ int addrconf_sysctl_forward(ctl_table *ctl, int write,
4028{ 4044{
4029 int *valp = ctl->data; 4045 int *valp = ctl->data;
4030 int val = *valp; 4046 int val = *valp;
4047 loff_t pos = *ppos;
4031 int ret; 4048 int ret;
4032 4049
4033 ret = proc_dointvec(ctl, write, buffer, lenp, ppos); 4050 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
4034 4051
4035 if (write) 4052 if (write)
4036 ret = addrconf_fixup_forwarding(ctl, valp, val); 4053 ret = addrconf_fixup_forwarding(ctl, valp, val);
4054 if (ret)
4055 *ppos = pos;
4037 return ret; 4056 return ret;
4038} 4057}
4039 4058
@@ -4075,8 +4094,11 @@ static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int old)
4075 if (p == &net->ipv6.devconf_dflt->disable_ipv6) 4094 if (p == &net->ipv6.devconf_dflt->disable_ipv6)
4076 return 0; 4095 return 0;
4077 4096
4078 if (!rtnl_trylock()) 4097 if (!rtnl_trylock()) {
4098 /* Restore the original values before restarting */
4099 *p = old;
4079 return restart_syscall(); 4100 return restart_syscall();
4101 }
4080 4102
4081 if (p == &net->ipv6.devconf_all->disable_ipv6) { 4103 if (p == &net->ipv6.devconf_all->disable_ipv6) {
4082 __s32 newf = net->ipv6.devconf_all->disable_ipv6; 4104 __s32 newf = net->ipv6.devconf_all->disable_ipv6;
@@ -4095,12 +4117,15 @@ int addrconf_sysctl_disable(ctl_table *ctl, int write,
4095{ 4117{
4096 int *valp = ctl->data; 4118 int *valp = ctl->data;
4097 int val = *valp; 4119 int val = *valp;
4120 loff_t pos = *ppos;
4098 int ret; 4121 int ret;
4099 4122
4100 ret = proc_dointvec(ctl, write, buffer, lenp, ppos); 4123 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
4101 4124
4102 if (write) 4125 if (write)
4103 ret = addrconf_disable_ipv6(ctl, valp, val); 4126 ret = addrconf_disable_ipv6(ctl, valp, val);
4127 if (ret)
4128 *ppos = pos;
4104 return ret; 4129 return ret;
4105} 4130}
4106 4131
@@ -4402,8 +4427,7 @@ static void __addrconf_sysctl_unregister(struct ipv6_devconf *p)
4402 4427
4403static void addrconf_sysctl_register(struct inet6_dev *idev) 4428static void addrconf_sysctl_register(struct inet6_dev *idev)
4404{ 4429{
4405 neigh_sysctl_register(idev->dev, idev->nd_parms, NET_IPV6, 4430 neigh_sysctl_register(idev->dev, idev->nd_parms, "ipv6",
4406 NET_IPV6_NEIGH, "ipv6",
4407 &ndisc_ifinfo_sysctl_change); 4431 &ndisc_ifinfo_sysctl_change);
4408 __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name, 4432 __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name,
4409 idev, &idev->cnf); 4433 idev, &idev->cnf);
@@ -4418,7 +4442,7 @@ static void addrconf_sysctl_unregister(struct inet6_dev *idev)
4418 4442
4419#endif 4443#endif
4420 4444
4421static int addrconf_init_net(struct net *net) 4445static int __net_init addrconf_init_net(struct net *net)
4422{ 4446{
4423 int err; 4447 int err;
4424 struct ipv6_devconf *all, *dflt; 4448 struct ipv6_devconf *all, *dflt;
@@ -4467,7 +4491,7 @@ err_alloc_all:
4467 return err; 4491 return err;
4468} 4492}
4469 4493
4470static void addrconf_exit_net(struct net *net) 4494static void __net_exit addrconf_exit_net(struct net *net)
4471{ 4495{
4472#ifdef CONFIG_SYSCTL 4496#ifdef CONFIG_SYSCTL
4473 __addrconf_sysctl_unregister(net->ipv6.devconf_dflt); 4497 __addrconf_sysctl_unregister(net->ipv6.devconf_dflt);