ipv4: make ip_local_reserved_ports per netns
authorWANG Cong <xiyou.wangcong@gmail.com>
Mon, 12 May 2014 23:04:53 +0000 (16:04 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 14 May 2014 19:31:45 +0000 (15:31 -0400)
ip_local_port_range is already per netns, so should ip_local_reserved_ports
be. And since it is none by default we don't actually need it when we don't
enable CONFIG_SYSCTL.

By the way, rename inet_is_reserved_local_port() to inet_is_local_reserved_port()

Cc: "David S. Miller" <davem@davemloft.net>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/ip.h
include/net/netns/ipv4.h
kernel/sysctl.c
net/ipv4/af_inet.c
net/ipv4/inet_connection_sock.c
net/ipv4/inet_hashtables.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/udp.c
net/sctp/socket.c

index 14c50a1..512bcd5 100644 (file)
@@ -208,11 +208,19 @@ static inline u64 snmp_fold_field64(void __percpu *mib, int offt, size_t syncp_o
 
 void inet_get_local_port_range(struct net *net, int *low, int *high);
 
-extern unsigned long *sysctl_local_reserved_ports;
-static inline int inet_is_reserved_local_port(int port)
+#if CONFIG_SYSCTL
+static inline int inet_is_local_reserved_port(struct net *net, int port)
 {
-       return test_bit(port, sysctl_local_reserved_ports);
+       if (!net->ipv4.sysctl_local_reserved_ports)
+               return 0;
+       return test_bit(port, net->ipv4.sysctl_local_reserved_ports);
 }
+#else
+static inline int inet_is_local_reserved_port(struct net *net, int port)
+{
+       return 0;
+}
+#endif
 
 extern int sysctl_ip_nonlocal_bind;
 
index 2f0cfad..aec5e12 100644 (file)
@@ -84,6 +84,10 @@ struct netns_ipv4 {
 
        atomic_t dev_addr_genid;
 
+#ifdef CONFIG_SYSCTL
+       unsigned long *sysctl_local_reserved_ports;
+#endif
+
 #ifdef CONFIG_IP_MROUTE
 #ifndef CONFIG_IP_MROUTE_MULTIPLE_TABLES
        struct mr_table         *mrt;
index 74f5b58..e36ae4b 100644 (file)
@@ -2501,11 +2501,11 @@ int proc_do_large_bitmap(struct ctl_table *table, int write,
        bool first = 1;
        size_t left = *lenp;
        unsigned long bitmap_len = table->maxlen;
-       unsigned long *bitmap = (unsigned long *) table->data;
+       unsigned long *bitmap = *(unsigned long **) table->data;
        unsigned long *tmp_bitmap = NULL;
        char tr_a[] = { '-', ',', '\n' }, tr_b[] = { ',', '\n', 0 }, c;
 
-       if (!bitmap_len || !left || (*ppos && !write)) {
+       if (!bitmap || !bitmap_len || !left || (*ppos && !write)) {
                *lenp = 0;
                return 0;
        }
index 211c0cc..279132b 100644 (file)
@@ -1705,13 +1705,9 @@ static int __init inet_init(void)
 
        BUILD_BUG_ON(sizeof(struct inet_skb_parm) > FIELD_SIZEOF(struct sk_buff, cb));
 
-       sysctl_local_reserved_ports = kzalloc(65536 / 8, GFP_KERNEL);
-       if (!sysctl_local_reserved_ports)
-               goto out;
-
        rc = proto_register(&tcp_prot, 1);
        if (rc)
-               goto out_free_reserved_ports;
+               goto out;
 
        rc = proto_register(&udp_prot, 1);
        if (rc)
@@ -1821,8 +1817,6 @@ out_unregister_udp_proto:
        proto_unregister(&udp_prot);
 out_unregister_tcp_proto:
        proto_unregister(&tcp_prot);
-out_free_reserved_ports:
-       kfree(sysctl_local_reserved_ports);
        goto out;
 }
 
index 12e502c..14d02ea 100644 (file)
@@ -29,9 +29,6 @@ const char inet_csk_timer_bug_msg[] = "inet_csk BUG: unknown timer value\n";
 EXPORT_SYMBOL(inet_csk_timer_bug_msg);
 #endif
 
-unsigned long *sysctl_local_reserved_ports;
-EXPORT_SYMBOL(sysctl_local_reserved_ports);
-
 void inet_get_local_port_range(struct net *net, int *low, int *high)
 {
        unsigned int seq;
@@ -113,7 +110,7 @@ again:
 
                smallest_size = -1;
                do {
-                       if (inet_is_reserved_local_port(rover))
+                       if (inet_is_local_reserved_port(net, rover))
                                goto next_nolock;
                        head = &hashinfo->bhash[inet_bhashfn(net, rover,
                                        hashinfo->bhash_size)];
index 8b9cf27..83331f1 100644 (file)
@@ -500,7 +500,7 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row,
                local_bh_disable();
                for (i = 1; i <= remaining; i++) {
                        port = low + (i + offset) % remaining;
-                       if (inet_is_reserved_local_port(port))
+                       if (inet_is_local_reserved_port(net, port))
                                continue;
                        head = &hinfo->bhash[inet_bhashfn(net, port,
                                        hinfo->bhash_size)];
index a33b9fb..79a007c 100644 (file)
@@ -436,13 +436,6 @@ static struct ctl_table ipv4_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
-       {
-               .procname       = "ip_local_reserved_ports",
-               .data           = NULL, /* initialized in sysctl_ipv4_init */
-               .maxlen         = 65536,
-               .mode           = 0644,
-               .proc_handler   = proc_do_large_bitmap,
-       },
        {
                .procname       = "igmp_max_memberships",
                .data           = &sysctl_igmp_max_memberships,
@@ -824,6 +817,13 @@ static struct ctl_table ipv4_net_table[] = {
                .mode           = 0644,
                .proc_handler   = ipv4_local_port_range,
        },
+       {
+               .procname       = "ip_local_reserved_ports",
+               .data           = &init_net.ipv4.sysctl_local_reserved_ports,
+               .maxlen         = 65536,
+               .mode           = 0644,
+               .proc_handler   = proc_do_large_bitmap,
+       },
        {
                .procname       = "ip_no_pmtu_disc",
                .data           = &init_net.ipv4.sysctl_ip_no_pmtu_disc,
@@ -876,8 +876,14 @@ static __net_init int ipv4_sysctl_init_net(struct net *net)
        if (net->ipv4.ipv4_hdr == NULL)
                goto err_reg;
 
+       net->ipv4.sysctl_local_reserved_ports = kzalloc(65536 / 8, GFP_KERNEL);
+       if (!net->ipv4.sysctl_local_reserved_ports)
+               goto err_ports;
+
        return 0;
 
+err_ports:
+       unregister_net_sysctl_table(net->ipv4.ipv4_hdr);
 err_reg:
        if (!net_eq(net, &init_net))
                kfree(table);
@@ -889,6 +895,7 @@ static __net_exit void ipv4_sysctl_exit_net(struct net *net)
 {
        struct ctl_table *table;
 
+       kfree(net->ipv4.sysctl_local_reserved_ports);
        table = net->ipv4.ipv4_hdr->ctl_table_arg;
        unregister_net_sysctl_table(net->ipv4.ipv4_hdr);
        kfree(table);
@@ -902,16 +909,6 @@ static __net_initdata struct pernet_operations ipv4_sysctl_ops = {
 static __init int sysctl_ipv4_init(void)
 {
        struct ctl_table_header *hdr;
-       struct ctl_table *i;
-
-       for (i = ipv4_table; i->procname; i++) {
-               if (strcmp(i->procname, "ip_local_reserved_ports") == 0) {
-                       i->data = sysctl_local_reserved_ports;
-                       break;
-               }
-       }
-       if (!i->procname)
-               return -EINVAL;
 
        hdr = register_net_sysctl(&init_net, "net/ipv4", ipv4_table);
        if (hdr == NULL)
index 54ea0a3..6729ea9 100644 (file)
@@ -246,7 +246,7 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
                        do {
                                if (low <= snum && snum <= high &&
                                    !test_bit(snum >> udptable->log, bitmap) &&
-                                   !inet_is_reserved_local_port(snum))
+                                   !inet_is_local_reserved_port(net, snum))
                                        goto found;
                                snum += rand;
                        } while (snum != first);
index e37b2cb..2af76ea 100644 (file)
@@ -5946,8 +5946,9 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
                /* Search for an available port. */
                int low, high, remaining, index;
                unsigned int rover;
+               struct net *net = sock_net(sk);
 
-               inet_get_local_port_range(sock_net(sk), &low, &high);
+               inet_get_local_port_range(net, &low, &high);
                remaining = (high - low) + 1;
                rover = prandom_u32() % remaining + low;
 
@@ -5955,7 +5956,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
                        rover++;
                        if ((rover < low) || (rover > high))
                                rover = low;
-                       if (inet_is_reserved_local_port(rover))
+                       if (inet_is_local_reserved_port(net, rover))
                                continue;
                        index = sctp_phashfn(sock_net(sk), rover);
                        head = &sctp_port_hashtable[index];