#include <linux/skbuff.h>
#include <linux/rcupdate.h>
#include <linux/seq_file.h>
+#include <linux/bitmap.h>
#include <linux/err.h>
#include <linux/sysctl.h>
int reachable_time;
int data[NEIGH_VAR_DATA_MAX];
+ DECLARE_BITMAP(data_state, NEIGH_VAR_DATA_MAX);
};
static inline void neigh_var_set(struct neigh_parms *p, int index, int val)
{
+ set_bit(index, p->data_state);
p->data[index] = val;
}
#define NEIGH_VAR(p, attr) ((p)->data[NEIGH_VAR_ ## attr])
#define NEIGH_VAR_SET(p, attr, val) neigh_var_set(p, NEIGH_VAR_ ## attr, val)
+static inline void neigh_parms_data_state_setall(struct neigh_parms *p)
+{
+ bitmap_fill(p->data_state, NEIGH_VAR_DATA_MAX);
+}
+
+static inline void neigh_parms_data_state_cleanall(struct neigh_parms *p)
+{
+ bitmap_zero(p->data_state, NEIGH_VAR_DATA_MAX);
+}
+
struct neigh_statistics {
unsigned long allocs; /* number of allocated neighs */
unsigned long destroys; /* number of destroyed neighs */
#include <linux/random.h>
#include <linux/string.h>
#include <linux/log2.h>
+#include <linux/inetdevice.h>
#define DEBUG
#define NEIGH_DEBUG 1
p->next = tbl->parms.next;
tbl->parms.next = p;
write_unlock_bh(&tbl->lock);
+
+ neigh_parms_data_state_cleanall(p);
}
return p;
}
return ret;
}
+static struct neigh_parms *neigh_get_dev_parms_rcu(struct net_device *dev,
+ int family)
+{
+ if (family == AF_INET)
+ return __in_dev_arp_parms_get_rcu(dev);
+ return NULL;
+}
+
+static void neigh_copy_dflt_parms(struct net *net, struct neigh_parms *p,
+ int index)
+{
+ struct net_device *dev;
+ int family = neigh_parms_family(p);
+
+ rcu_read_lock();
+ for_each_netdev_rcu(net, dev) {
+ struct neigh_parms *dst_p =
+ neigh_get_dev_parms_rcu(dev, family);
+
+ if (dst_p && !test_bit(index, dst_p->data_state))
+ dst_p->data[index] = p->data[index];
+ }
+ rcu_read_unlock();
+}
+
+static void neigh_proc_update(struct ctl_table *ctl, int write)
+{
+ struct net_device *dev = ctl->extra1;
+ struct neigh_parms *p = ctl->extra2;
+ struct net *net = p->net;
+ int index = (int *) ctl->data - p->data;
+
+ if (!write)
+ return;
+
+ set_bit(index, p->data_state);
+ if (!dev) /* NULL dev means this is default value */
+ neigh_copy_dflt_parms(net, p, index);
+}
+
static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write,
void __user *buffer,
size_t *lenp, loff_t *ppos)
{
struct ctl_table tmp = *ctl;
+ int ret;
tmp.extra1 = &zero;
tmp.extra2 = &int_max;
- return proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
+ ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
+ neigh_proc_update(ctl, write);
+ return ret;
}
int neigh_proc_dointvec(struct ctl_table *ctl, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
- return proc_dointvec(ctl, write, buffer, lenp, ppos);
+ int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
+
+ neigh_proc_update(ctl, write);
+ return ret;
}
EXPORT_SYMBOL(neigh_proc_dointvec);
void __user *buffer,
size_t *lenp, loff_t *ppos)
{
- return proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
+ int ret = proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
+
+ neigh_proc_update(ctl, write);
+ return ret;
}
EXPORT_SYMBOL(neigh_proc_dointvec_jiffies);
void __user *buffer,
size_t *lenp, loff_t *ppos)
{
- return proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos);
+ int ret = proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos);
+
+ neigh_proc_update(ctl, write);
+ return ret;
}
int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write,
void __user *buffer,
size_t *lenp, loff_t *ppos)
{
- return proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
+ int ret = proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
+
+ neigh_proc_update(ctl, write);
+ return ret;
}
EXPORT_SYMBOL(neigh_proc_dointvec_ms_jiffies);
void __user *buffer,
size_t *lenp, loff_t *ppos)
{
- return proc_unres_qlen(ctl, write, buffer, lenp, ppos);
+ int ret = proc_unres_qlen(ctl, write, buffer, lenp, ppos);
+
+ neigh_proc_update(ctl, write);
+ return ret;
}
#define NEIGH_PARMS_DATA_OFFSET(index) \
for (i = 0; i < ARRAY_SIZE(t->neigh_vars); i++) {
t->neigh_vars[i].data += (long) p;
t->neigh_vars[i].extra1 = dev;
+ t->neigh_vars[i].extra2 = p;
}
if (dev) {