aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Pirko <jiri@resnulli.us>2013-12-07 13:26:56 -0500
committerDavid S. Miller <davem@davemloft.net>2013-12-09 20:56:12 -0500
commit1d4c8c29841b9991cdf3c7cc4ba7f96a94f104ca (patch)
tree735b39613dad7918e27f2348fa07c6f101d27e17
parent73af614aedd221df8495fc8c9993c50e87f899f2 (diff)
neigh: restore old behaviour of default parms values
Previously inet devices were only constructed when addresses are added. Therefore the default neigh parms values they get are the ones at the time of these operations. Now that we're creating inet devices earlier, this changes the behaviour of default neigh parms values in an incompatible way (see bug #8519). This patch creates a compromise by setting the default values at the same point as before but only for those that have not been explicitly set by the user since the inet device's creation. Introduced by: commit 8030f54499925d073a88c09f30d5d844fb1b3190 Author: Herbert Xu <herbert@gondor.apana.org.au> Date: Thu Feb 22 01:53:47 2007 +0900 [IPV4] devinet: Register inetdev earlier. Signed-off-by: Jiri Pirko <jiri@resnulli.us> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/inetdevice.h7
-rw-r--r--include/net/neighbour.h13
-rw-r--r--net/core/neighbour.c74
-rw-r--r--net/ipv4/devinet.c2
-rw-r--r--net/ipv4/ipmr.c2
5 files changed, 92 insertions, 6 deletions
diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
index 0d678aefe69d..ae174ca565c9 100644
--- a/include/linux/inetdevice.h
+++ b/include/linux/inetdevice.h
@@ -220,6 +220,13 @@ static inline struct in_device *__in_dev_get_rtnl(const struct net_device *dev)
220 return rtnl_dereference(dev->ip_ptr); 220 return rtnl_dereference(dev->ip_ptr);
221} 221}
222 222
223static inline struct neigh_parms *__in_dev_arp_parms_get_rcu(const struct net_device *dev)
224{
225 struct in_device *in_dev = __in_dev_get_rcu(dev);
226
227 return in_dev ? in_dev->arp_parms : NULL;
228}
229
223void in_dev_finish_destroy(struct in_device *idev); 230void in_dev_finish_destroy(struct in_device *idev);
224 231
225static inline void in_dev_put(struct in_device *idev) 232static inline void in_dev_put(struct in_device *idev)
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index 95615c9ad13a..41b1ce6c96a8 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -21,6 +21,7 @@
21#include <linux/skbuff.h> 21#include <linux/skbuff.h>
22#include <linux/rcupdate.h> 22#include <linux/rcupdate.h>
23#include <linux/seq_file.h> 23#include <linux/seq_file.h>
24#include <linux/bitmap.h>
24 25
25#include <linux/err.h> 26#include <linux/err.h>
26#include <linux/sysctl.h> 27#include <linux/sysctl.h>
@@ -81,16 +82,28 @@ struct neigh_parms {
81 82
82 int reachable_time; 83 int reachable_time;
83 int data[NEIGH_VAR_DATA_MAX]; 84 int data[NEIGH_VAR_DATA_MAX];
85 DECLARE_BITMAP(data_state, NEIGH_VAR_DATA_MAX);
84}; 86};
85 87
86static inline void neigh_var_set(struct neigh_parms *p, int index, int val) 88static inline void neigh_var_set(struct neigh_parms *p, int index, int val)
87{ 89{
90 set_bit(index, p->data_state);
88 p->data[index] = val; 91 p->data[index] = val;
89} 92}
90 93
91#define NEIGH_VAR(p, attr) ((p)->data[NEIGH_VAR_ ## attr]) 94#define NEIGH_VAR(p, attr) ((p)->data[NEIGH_VAR_ ## attr])
92#define NEIGH_VAR_SET(p, attr, val) neigh_var_set(p, NEIGH_VAR_ ## attr, val) 95#define NEIGH_VAR_SET(p, attr, val) neigh_var_set(p, NEIGH_VAR_ ## attr, val)
93 96
97static inline void neigh_parms_data_state_setall(struct neigh_parms *p)
98{
99 bitmap_fill(p->data_state, NEIGH_VAR_DATA_MAX);
100}
101
102static inline void neigh_parms_data_state_cleanall(struct neigh_parms *p)
103{
104 bitmap_zero(p->data_state, NEIGH_VAR_DATA_MAX);
105}
106
94struct neigh_statistics { 107struct neigh_statistics {
95 unsigned long allocs; /* number of allocated neighs */ 108 unsigned long allocs; /* number of allocated neighs */
96 unsigned long destroys; /* number of destroyed neighs */ 109 unsigned long destroys; /* number of destroyed neighs */
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 65ead080167b..c4a7879bfb15 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -38,6 +38,7 @@
38#include <linux/random.h> 38#include <linux/random.h>
39#include <linux/string.h> 39#include <linux/string.h>
40#include <linux/log2.h> 40#include <linux/log2.h>
41#include <linux/inetdevice.h>
41 42
42#define DEBUG 43#define DEBUG
43#define NEIGH_DEBUG 1 44#define NEIGH_DEBUG 1
@@ -1464,6 +1465,8 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
1464 p->next = tbl->parms.next; 1465 p->next = tbl->parms.next;
1465 tbl->parms.next = p; 1466 tbl->parms.next = p;
1466 write_unlock_bh(&tbl->lock); 1467 write_unlock_bh(&tbl->lock);
1468
1469 neigh_parms_data_state_cleanall(p);
1467 } 1470 }
1468 return p; 1471 return p;
1469} 1472}
@@ -2813,22 +2816,68 @@ static int proc_unres_qlen(struct ctl_table *ctl, int write,
2813 return ret; 2816 return ret;
2814} 2817}
2815 2818
2819static struct neigh_parms *neigh_get_dev_parms_rcu(struct net_device *dev,
2820 int family)
2821{
2822 if (family == AF_INET)
2823 return __in_dev_arp_parms_get_rcu(dev);
2824 return NULL;
2825}
2826
2827static void neigh_copy_dflt_parms(struct net *net, struct neigh_parms *p,
2828 int index)
2829{
2830 struct net_device *dev;
2831 int family = neigh_parms_family(p);
2832
2833 rcu_read_lock();
2834 for_each_netdev_rcu(net, dev) {
2835 struct neigh_parms *dst_p =
2836 neigh_get_dev_parms_rcu(dev, family);
2837
2838 if (dst_p && !test_bit(index, dst_p->data_state))
2839 dst_p->data[index] = p->data[index];
2840 }
2841 rcu_read_unlock();
2842}
2843
2844static void neigh_proc_update(struct ctl_table *ctl, int write)
2845{
2846 struct net_device *dev = ctl->extra1;
2847 struct neigh_parms *p = ctl->extra2;
2848 struct net *net = p->net;
2849 int index = (int *) ctl->data - p->data;
2850
2851 if (!write)
2852 return;
2853
2854 set_bit(index, p->data_state);
2855 if (!dev) /* NULL dev means this is default value */
2856 neigh_copy_dflt_parms(net, p, index);
2857}
2858
2816static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write, 2859static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write,
2817 void __user *buffer, 2860 void __user *buffer,
2818 size_t *lenp, loff_t *ppos) 2861 size_t *lenp, loff_t *ppos)
2819{ 2862{
2820 struct ctl_table tmp = *ctl; 2863 struct ctl_table tmp = *ctl;
2864 int ret;
2821 2865
2822 tmp.extra1 = &zero; 2866 tmp.extra1 = &zero;
2823 tmp.extra2 = &int_max; 2867 tmp.extra2 = &int_max;
2824 2868
2825 return proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); 2869 ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
2870 neigh_proc_update(ctl, write);
2871 return ret;
2826} 2872}
2827 2873
2828int neigh_proc_dointvec(struct ctl_table *ctl, int write, 2874int neigh_proc_dointvec(struct ctl_table *ctl, int write,
2829 void __user *buffer, size_t *lenp, loff_t *ppos) 2875 void __user *buffer, size_t *lenp, loff_t *ppos)
2830{ 2876{
2831 return proc_dointvec(ctl, write, buffer, lenp, ppos); 2877 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
2878
2879 neigh_proc_update(ctl, write);
2880 return ret;
2832} 2881}
2833EXPORT_SYMBOL(neigh_proc_dointvec); 2882EXPORT_SYMBOL(neigh_proc_dointvec);
2834 2883
@@ -2836,7 +2885,10 @@ int neigh_proc_dointvec_jiffies(struct ctl_table *ctl, int write,
2836 void __user *buffer, 2885 void __user *buffer,
2837 size_t *lenp, loff_t *ppos) 2886 size_t *lenp, loff_t *ppos)
2838{ 2887{
2839 return proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos); 2888 int ret = proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
2889
2890 neigh_proc_update(ctl, write);
2891 return ret;
2840} 2892}
2841EXPORT_SYMBOL(neigh_proc_dointvec_jiffies); 2893EXPORT_SYMBOL(neigh_proc_dointvec_jiffies);
2842 2894
@@ -2844,14 +2896,20 @@ static int neigh_proc_dointvec_userhz_jiffies(struct ctl_table *ctl, int write,
2844 void __user *buffer, 2896 void __user *buffer,
2845 size_t *lenp, loff_t *ppos) 2897 size_t *lenp, loff_t *ppos)
2846{ 2898{
2847 return proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos); 2899 int ret = proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos);
2900
2901 neigh_proc_update(ctl, write);
2902 return ret;
2848} 2903}
2849 2904
2850int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write, 2905int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write,
2851 void __user *buffer, 2906 void __user *buffer,
2852 size_t *lenp, loff_t *ppos) 2907 size_t *lenp, loff_t *ppos)
2853{ 2908{
2854 return proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos); 2909 int ret = proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
2910
2911 neigh_proc_update(ctl, write);
2912 return ret;
2855} 2913}
2856EXPORT_SYMBOL(neigh_proc_dointvec_ms_jiffies); 2914EXPORT_SYMBOL(neigh_proc_dointvec_ms_jiffies);
2857 2915
@@ -2859,7 +2917,10 @@ static int neigh_proc_dointvec_unres_qlen(struct ctl_table *ctl, int write,
2859 void __user *buffer, 2917 void __user *buffer,
2860 size_t *lenp, loff_t *ppos) 2918 size_t *lenp, loff_t *ppos)
2861{ 2919{
2862 return proc_unres_qlen(ctl, write, buffer, lenp, ppos); 2920 int ret = proc_unres_qlen(ctl, write, buffer, lenp, ppos);
2921
2922 neigh_proc_update(ctl, write);
2923 return ret;
2863} 2924}
2864 2925
2865#define NEIGH_PARMS_DATA_OFFSET(index) \ 2926#define NEIGH_PARMS_DATA_OFFSET(index) \
@@ -2962,6 +3023,7 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
2962 for (i = 0; i < ARRAY_SIZE(t->neigh_vars); i++) { 3023 for (i = 0; i < ARRAY_SIZE(t->neigh_vars); i++) {
2963 t->neigh_vars[i].data += (long) p; 3024 t->neigh_vars[i].data += (long) p;
2964 t->neigh_vars[i].extra1 = dev; 3025 t->neigh_vars[i].extra1 = dev;
3026 t->neigh_vars[i].extra2 = p;
2965 } 3027 }
2966 3028
2967 if (dev) { 3029 if (dev) {
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index e1c19535fe38..43065be36301 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -500,6 +500,7 @@ static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
500 return -ENOBUFS; 500 return -ENOBUFS;
501 } 501 }
502 ipv4_devconf_setall(in_dev); 502 ipv4_devconf_setall(in_dev);
503 neigh_parms_data_state_setall(in_dev->arp_parms);
503 if (ifa->ifa_dev != in_dev) { 504 if (ifa->ifa_dev != in_dev) {
504 WARN_ON(ifa->ifa_dev); 505 WARN_ON(ifa->ifa_dev);
505 in_dev_hold(in_dev); 506 in_dev_hold(in_dev);
@@ -747,6 +748,7 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
747 goto errout; 748 goto errout;
748 749
749 ipv4_devconf_setall(in_dev); 750 ipv4_devconf_setall(in_dev);
751 neigh_parms_data_state_setall(in_dev->arp_parms);
750 in_dev_hold(in_dev); 752 in_dev_hold(in_dev);
751 753
752 if (tb[IFA_ADDRESS] == NULL) 754 if (tb[IFA_ADDRESS] == NULL)
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 62212c772a4b..421a24934ffd 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -425,6 +425,7 @@ struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v)
425 goto failure; 425 goto failure;
426 426
427 ipv4_devconf_setall(in_dev); 427 ipv4_devconf_setall(in_dev);
428 neigh_parms_data_state_setall(in_dev->arp_parms);
428 IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0; 429 IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0;
429 430
430 if (dev_open(dev)) 431 if (dev_open(dev))
@@ -517,6 +518,7 @@ static struct net_device *ipmr_reg_vif(struct net *net, struct mr_table *mrt)
517 } 518 }
518 519
519 ipv4_devconf_setall(in_dev); 520 ipv4_devconf_setall(in_dev);
521 neigh_parms_data_state_setall(in_dev->arp_parms);
520 IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0; 522 IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0;
521 rcu_read_unlock(); 523 rcu_read_unlock();
522 524