[NETNS][FRAGS]: Duplicate sysctl tables for new namespaces.
Pavel Emelyanov [Tue, 22 Jan 2008 14:08:36 +0000 (06:08 -0800)]
Each namespace has to have own tables to tune their
different parameters, so duplicate the tables and
register them.

All the tables in sub-namespaces are temporarily made
read-only.

Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

include/net/netns/ipv4.h
include/net/netns/ipv6.h
net/ipv4/ip_fragment.c
net/ipv6/reassembly.c

index 80680e0..15a0b05 100644 (file)
@@ -16,6 +16,7 @@ struct sock;
 struct netns_ipv4 {
 #ifdef CONFIG_SYSCTL
        struct ctl_table_header *forw_hdr;
+       struct ctl_table_header *frags_hdr;
 #endif
        struct ipv4_devconf     *devconf_all;
        struct ipv4_devconf     *devconf_dflt;
index 057c8e4..87ab56a 100644 (file)
@@ -12,6 +12,7 @@ struct ctl_table_header;
 struct netns_sysctl_ipv6 {
 #ifdef CONFIG_SYSCTL
        struct ctl_table_header *table;
+       struct ctl_table_header *frags_hdr;
 #endif
        struct inet_frags_ctl frags;
        int bindv6only;
index 4f01334..c51e1a1 100644 (file)
@@ -661,17 +661,53 @@ static struct ctl_table ip4_frags_ctl_table[] = {
 
 static int ip4_frags_ctl_register(struct net *net)
 {
+       struct ctl_table *table;
        struct ctl_table_header *hdr;
 
-       hdr = register_net_sysctl_table(net, net_ipv4_ctl_path,
-                       ip4_frags_ctl_table);
-       return hdr == NULL ? -ENOMEM : 0;
+       table = ip4_frags_ctl_table;
+       if (net != &init_net) {
+               table = kmemdup(table, sizeof(ip4_frags_ctl_table), GFP_KERNEL);
+               if (table == NULL)
+                       goto err_alloc;
+
+               table[0].mode &= ~0222;
+               table[1].mode &= ~0222;
+               table[2].mode &= ~0222;
+               table[3].mode &= ~0222;
+               table[4].mode &= ~0222;
+       }
+
+       hdr = register_net_sysctl_table(net, net_ipv4_ctl_path, table);
+       if (hdr == NULL)
+               goto err_reg;
+
+       net->ipv4.frags_hdr = hdr;
+       return 0;
+
+err_reg:
+       if (net != &init_net)
+               kfree(table);
+err_alloc:
+       return -ENOMEM;
+}
+
+static void ip4_frags_ctl_unregister(struct net *net)
+{
+       struct ctl_table *table;
+
+       table = net->ipv4.frags_hdr->ctl_table_arg;
+       unregister_net_sysctl_table(net->ipv4.frags_hdr);
+       kfree(table);
 }
 #else
 static inline int ip4_frags_ctl_register(struct net *net)
 {
        return 0;
 }
+
+static inline void ip4_frags_ctl_unregister(struct net *net)
+{
+}
 #endif
 
 static int ipv4_frags_init_net(struct net *net)
index 241b2cc..0300dcb 100644 (file)
@@ -670,17 +670,52 @@ static struct ctl_table ip6_frags_ctl_table[] = {
 
 static int ip6_frags_sysctl_register(struct net *net)
 {
+       struct ctl_table *table;
        struct ctl_table_header *hdr;
 
-       hdr = register_net_sysctl_table(net, net_ipv6_ctl_path,
-                       ip6_frags_ctl_table);
-       return hdr == NULL ? -ENOMEM : 0;
+       table = ip6_frags_ctl_table;
+       if (net != &init_net) {
+               table = kmemdup(table, sizeof(ip6_frags_ctl_table), GFP_KERNEL);
+               if (table == NULL)
+                       goto err_alloc;
+
+               table[0].mode &= ~0222;
+               table[1].mode &= ~0222;
+               table[2].mode &= ~0222;
+               table[3].mode &= ~0222;
+       }
+
+       hdr = register_net_sysctl_table(net, net_ipv6_ctl_path, table);
+       if (hdr == NULL)
+               goto err_reg;
+
+       net->ipv6.sysctl.frags_hdr = hdr;
+       return 0;
+
+err_reg:
+       if (net != &init_net)
+               kfree(table);
+err_alloc:
+       return -ENOMEM;
+}
+
+static void ip6_frags_sysctl_unregister(struct net *net)
+{
+       struct ctl_table *table;
+
+       table = net->ipv6.sysctl.frags_hdr->ctl_table_arg;
+       unregister_net_sysctl_table(net->ipv6.sysctl.frags_hdr);
+       kfree(table);
 }
 #else
 static inline int ip6_frags_sysctl_register(struct net *net)
 {
        return 0;
 }
+
+static inline void ip6_frags_sysctl_unregister(struct net *net)
+{
+}
 #endif
 
 static int ipv6_frags_init_net(struct net *net)