From: Eric W. Biederman <[EMAIL PROTECTED]> - unquoted The user interface is: register_net_sysctl_table and unregister_net_sysctl_table. Very much like the current interface except there is an network namespace parameter.
This this any sysctl in the net_root_table and it's subdirectories are registered with register_net_sysctl shows up only to tasks in the same network namespace. All other sysctls continue to be globally visible. Signed-off-by: Eric W. Biederman <[EMAIL PROTECTED]> --- include/linux/sysctl.h | 7 ++++ include/net/sock.h | 1 + kernel/sysctl.c | 71 ++++++++++++++++++++++++++++++++++++++++++- net/core/sysctl_net_core.c | 5 +++ net/sysctl_net.c | 20 ++++++++++++ 5 files changed, 102 insertions(+), 2 deletions(-) diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 8eba2d2..286e723 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -1044,6 +1044,13 @@ struct ctl_table_header * register_sysctl_table(ctl_table * table); void unregister_sysctl_table(struct ctl_table_header * table); +#ifdef CONFIG_NET +#include <linux/net_namespace_type.h> +extern struct ctl_table_header *register_net_sysctl_table(net_t net, struct ctl_table *table); +extern void unregister_net_sysctl_table(struct ctl_table_header *header); +DECLARE_PER_NET(struct ctl_table, net_root_table[]); +#endif + #else /* __KERNEL__ */ #endif /* __KERNEL__ */ diff --git a/include/net/sock.h b/include/net/sock.h index 5bf6bb5..01a2781 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1414,6 +1414,7 @@ extern void sk_init(void); #ifdef CONFIG_SYSCTL extern struct ctl_table core_table[]; +DECLARE_PER_NET(struct ctl_table, multi_core_table[]); #endif extern int sysctl_optmem_max; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 7da313e..ae6a424 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -45,6 +45,7 @@ #include <linux/syscalls.h> #include <linux/nfs_fs.h> #include <linux/acpi.h> +#include <net/net_namespace.h> #include <asm/uaccess.h> #include <asm/processor.h> @@ -135,6 +136,10 @@ static int proc_do_cad_pid(ctl_table *table, int write, struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos); #endif +#ifdef CONFIG_NET +static DEFINE_PER_NET(struct ctl_table_header, net_table_header); +#endif + static ctl_table root_table[]; static struct ctl_table_header root_table_header = { root_table, LIST_HEAD_INIT(root_table_header.ctl_entry) }; @@ -1059,6 +1064,7 @@ struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev) { struct ctl_table_header *head; struct list_head *tmp; + net_t net = current->nsproxy->net_ns; spin_lock(&sysctl_lock); if (prev) { tmp = &prev->ctl_entry; @@ -1076,6 +1082,10 @@ struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev) next: tmp = tmp->next; if (tmp == &root_table_header.ctl_entry) +#ifdef CONFIG_NET + tmp = &per_net(net_table_header, net).ctl_entry; + else if (tmp == &per_net(net_table_header, net).ctl_entry) +#endif break; } spin_unlock(&sysctl_lock); @@ -1290,7 +1300,8 @@ int do_sysctl_strategy (ctl_table *table, * This routine returns %NULL on a failure to register, and a pointer * to the table header on success. */ -struct ctl_table_header *register_sysctl_table(ctl_table * table) +static struct ctl_table_header *__register_sysctl_table( + struct ctl_table_header *root, ctl_table * table) { struct ctl_table_header *tmp; tmp = kmalloc(sizeof(struct ctl_table_header), GFP_KERNEL); @@ -1301,11 +1312,16 @@ struct ctl_table_header *register_sysctl_table(ctl_table * table) tmp->used = 0; tmp->unregistering = NULL; spin_lock(&sysctl_lock); - list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry); + list_add_tail(&tmp->ctl_entry, &root->ctl_entry); spin_unlock(&sysctl_lock); return tmp; } +struct ctl_table_header *register_sysctl_table(ctl_table *table) +{ + return __register_sysctl_table(&root_table_header, table); +} + /** * unregister_sysctl_table - unregister a sysctl table hierarchy * @header: the header returned from register_sysctl_table @@ -1322,6 +1338,57 @@ void unregister_sysctl_table(struct ctl_table_header * header) kfree(header); } +#ifdef CONFIG_NET + +static void *fixup_per_net_addr(net_t net, void *addr) +{ + char *ptr = addr; + if ((ptr >= __per_net_start) && (ptr < __per_net_end)) + ptr += __per_net_offset(net); + return ptr; +} + +static void sysctl_net_table_fixup(net_t net, struct ctl_table *table) +{ + for (; table->ctl_name || table->procname; table++) { + table->child = fixup_per_net_addr(net, table->child); + table->data = fixup_per_net_addr(net, table->data); + table->extra1 = fixup_per_net_addr(net, table->extra1); + table->extra2 = fixup_per_net_addr(net, table->extra2); + + /* Whee recursive functions on the kernel stack */ + if (table->child) + sysctl_net_table_fixup(net, table->child); + } +} + +static void sysctl_net_init(net_t net) +{ + struct ctl_table *table = per_net(net_root_table, net); + + sysctl_net_table_fixup(net, table); + per_net(net_table_header, net).ctl_table = table; + + INIT_LIST_HEAD(&per_net(net_table_header, net).ctl_entry); +} + +struct ctl_table_header *register_net_sysctl_table(net_t net, ctl_table *table) +{ + if (!per_net(net_table_header, net).ctl_table) + sysctl_net_init(net); + sysctl_net_table_fixup(net, table); + return __register_sysctl_table(&per_net(net_table_header, net), table); +} +EXPORT_SYMBOL_GPL(register_net_sysctl_table); + +void unregister_net_sysctl_table(struct ctl_table_header *header) +{ + return unregister_sysctl_table(header); +} +EXPORT_SYMBOL_GPL(unregister_net_sysctl_table); +#endif + + #else /* !CONFIG_SYSCTL */ struct ctl_table_header * register_sysctl_table(ctl_table * table, int insert_at_head) diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index 176ad08..76f7a29 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c @@ -125,3 +125,8 @@ ctl_table core_table[] = { }, { .ctl_name = 0 } }; + +DEFINE_PER_NET(struct ctl_table, multi_core_table[]) = { + /* Stub for holding per network namespace sysctls */ + {} +}; diff --git a/net/sysctl_net.c b/net/sysctl_net.c index cd4eafb..359c163 100644 --- a/net/sysctl_net.c +++ b/net/sysctl_net.c @@ -54,3 +54,23 @@ struct ctl_table net_table[] = { #endif { 0 }, }; + +DEFINE_PER_NET(struct ctl_table, multi_net_table[]) = { + { + .ctl_name = NET_CORE, + .procname = "core", + .mode = 0555, + .child = __per_net_base(multi_core_table), + }, + {}, +}; + +DEFINE_PER_NET(struct ctl_table, net_root_table[]) = { + { + .ctl_name = CTL_NET, + .procname = "net", + .mode = 0555, + .child = __per_net_base(multi_net_table), + }, + {}, +}; -- 1.4.4.1.g278f - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html