[PATCH 01/13] SCTP: Preparation for namespace enablement

From: Jan Ariyasu
Date: Sat Aug 04 2012 - 17:32:10 EST


Introduce data structures and break up module initialization and
exit into subroutines with common functionality for namespace
registration.

Signed-off-by: Jan Ariyasu <jan.ariyasu@xxxxxx>
---
include/net/sctp/structs.h | 150 ++++++++++++++++++++
net/sctp/protocol.c | 332 +++++++++++++++++++++++++++-----------------
2 files changed, 353 insertions(+), 129 deletions(-)

diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index fc5e600..bc65718 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -77,6 +77,8 @@ union sctp_addr {

/* Forward declarations for data structures. */
struct sctp_globals;
+struct sctp_ns_globals;
+struct sctp_net_params;
struct sctp_endpoint;
struct sctp_association;
struct sctp_transport;
@@ -293,6 +295,135 @@ extern struct sctp_globals {
#define sctp_rwnd_upd_shift (sctp_globals.rwnd_update_shift)
#define sctp_max_autoclose (sctp_globals.max_autoclose)

+struct sctp_net_params {
+ /* RFC2960 Section 14. Suggested SCTP Protocol Parameter Values
+ *
+ * The following protocol parameters are RECOMMENDED:
+ *
+ * RTO.Initial - 3 seconds
+ * RTO.Min - 1 second
+ * RTO.Max - 60 seconds
+ * RTO.Alpha - 1/8 (3 when converted to right shifts.)
+ * RTO.Beta - 1/4 (2 when converted to right shifts.)
+ */
+ unsigned int rto_initial;
+ unsigned int rto_min;
+ unsigned int rto_max;
+
+ /* Note: rto_alpha and rto_beta are really defined as inverse
+ * powers of two to facilitate integer operations.
+ */
+ int rto_alpha;
+ int rto_beta;
+
+ /* Max.Burst - 4 */
+ int max_burst;
+
+ /* Whether Cookie Preservative is enabled(1) or not(0) */
+ int cookie_preserve_enable;
+
+ /* Valid.Cookie.Life - 60 seconds */
+ unsigned int valid_cookie_life;
+
+ /* Delayed SACK timeout 200ms default*/
+ unsigned int sack_timeout;
+
+ /* HB.interval - 30 seconds */
+ unsigned int hb_interval;
+
+ /* Association.Max.Retrans - 10 attempts
+ * Path.Max.Retrans - 5 attempts (per destination address)
+ * Max.Init.Retransmits - 8 attempts
+ */
+ int max_retrans_association;
+ int max_retrans_path;
+ int max_retrans_init;
+
+ /* Potentially-Failed.Max.Retrans sysctl value
+ * taken from:
+ * http://tools.ietf.org/html/draft-nishida-tsvwg-sctp-failover-05
+ */
+ int pf_retrans;
+
+ /*
+ * Policy for preforming sctp/socket accounting
+ * 0 - do socket level accounting, all assocs share sk_sndbuf
+ * 1 - do sctp accounting, each asoc may use sk_sndbuf bytes
+ */
+ int sndbuf_policy;
+
+ /*
+ * Policy for preforming sctp/socket accounting
+ * 0 - do socket level accounting, all assocs share sk_rcvbuf
+ * 1 - do sctp accounting, each asoc may use sk_rcvbuf bytes
+ */
+ int rcvbuf_policy;
+
+ /* The following variables are implementation specific. */
+
+ /* Default initialization values to be applied to new associations. */
+ __u16 max_instreams;
+ __u16 max_outstreams;
+
+
+ /* This is the hash of all endpoints. */
+ int ep_hashsize;
+ struct sctp_hashbucket *ep_hashtable;
+
+ /* This is the hash of all associations. */
+ int assoc_hashsize;
+ struct sctp_hashbucket *assoc_hashtable;
+
+ /* This is the sctp port control hash. */
+ int port_hashsize;
+ struct sctp_bind_hashbucket *port_hashtable;
+
+ /* This is the global local address list.
+ * We actively maintain this complete list of addresses on
+ * the system by catching address add/delete events.
+ *
+ * It is a list of sctp_sockaddr_entry.
+ */
+ struct list_head local_addr_list;
+
+ /* Lock that protects the local_addr_list writers */
+ spinlock_t addr_list_lock;
+
+ /* Address Event Parameters */
+ int default_auto_asconf;
+ struct list_head addr_waitq;
+ struct timer_list addr_wq_timer;
+ struct list_head auto_asconf_splist;
+ spinlock_t addr_wq_lock;
+
+ /* Flag to indicate if addip is enabled. */
+ int addip_enable;
+ int addip_noauth_enable;
+
+ /* Flag to indicate if PR-SCTP is enabled. */
+ int prsctp_enable;
+
+ /* Flag to idicate if SCTP-AUTH is enabled */
+ int auth_enable;
+
+ /*
+ * Policy to control SCTP IPv4 address scoping
+ * 0 - Disable IPv4 address scoping
+ * 1 - Enable IPv4 address scoping
+ * 2 - Selectively allow only IPv4 private addresses
+ * 3 - Selectively allow only IPv4 link local address
+ */
+ int ipv4_scope_policy;
+
+ /* Threshold for rwnd update SACKS. Receive buffer shifted this many
+ * bits is an indicator of when to send and window update SACK.
+ */
+ int rwnd_update_shift;
+
+ /* Threshold for autoclose timeout, in seconds. */
+ unsigned long max_autoclose;
+};
+
/* SCTP Socket type: UDP or TCP style. */
typedef enum {
SCTP_SOCKET_UDP = 0,
@@ -2056,4 +2187,23 @@ typedef struct {
atomic_t *counter;
} sctp_dbg_objcnt_entry_t;

+
+/* Structure for keeping track of namespace globals */
+struct sctp_ns_globals {
+ struct sock *sctp_ctl_sock;
+ struct sctp_net_params protocol_params;
+ struct idr assocs_id;
+ spinlock_t assocs_id_lock;
+#ifdef CONFIG_SYSCTL
+ struct ctl_table_header *sctp_sysctl_tbl;
+#endif
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *sctp_proc_dir;
+ struct proc_dir_entry *sctp_proc_snmp;
+ struct proc_dir_entry *sctp_proc_assocs;
+ struct proc_dir_entry *sctp_proc_eps;
+ struct proc_dir_entry *sctp_proc_remaddr;
+#endif
+};
+
#endif /* __sctp_structs_h__ */
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 1f89c4e..cafdaac 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -105,13 +105,11 @@ struct sock *sctp_get_ctl_sock(void)
/* Set up the proc fs entry for the SCTP protocol. */
static __init int sctp_proc_init(void)
{
- if (percpu_counter_init(&sctp_sockets_allocated, 0))
- goto out_nomem;
#ifdef CONFIG_PROC_FS
if (!proc_net_sctp) {
proc_net_sctp = proc_mkdir("sctp", init_net.proc_net);
if (!proc_net_sctp)
- goto out_free_percpu;
+ goto out_nomem;
}

if (sctp_snmp_proc_init())
@@ -136,14 +134,12 @@ out_snmp_proc_init:
proc_net_sctp = NULL;
remove_proc_entry("sctp", init_net.proc_net);
}
-out_free_percpu:
- percpu_counter_destroy(&sctp_sockets_allocated);
-#else
- return 0;
-#endif /* CONFIG_PROC_FS */

out_nomem:
return -ENOMEM;
+#else
+ return 0;
+#endif /* CONFIG_PROC_FS */
}

/* Clean up the proc fs entry for the SCTP protocol.
@@ -163,7 +159,6 @@ static void sctp_proc_exit(void)
remove_proc_entry("sctp", init_net.proc_net);
}
#endif
- percpu_counter_destroy(&sctp_sockets_allocated);
}

/* Private helper to extract ipv4 address and stash them in
@@ -1194,105 +1189,91 @@ static void sctp_v4_del_protocol(void)
unregister_inetaddr_notifier(&sctp_inetaddr_notifier);
}

-/* Initialize the universe into something sensible. */
-SCTP_STATIC __init int sctp_init(void)
+static void sctp_global_param_init(void)
{
- int i;
- int status = -EINVAL;
- unsigned long goal;
- unsigned long limit;
- int max_share;
- int order;
-
- /* SCTP_DEBUG sanity check. */
- if (!sctp_sanity_check())
- goto out;
-
- /* Allocate bind_bucket and chunk caches. */
- status = -ENOBUFS;
- sctp_bucket_cachep = kmem_cache_create("sctp_bind_bucket",
- sizeof(struct sctp_bind_bucket),
- 0, SLAB_HWCACHE_ALIGN,
- NULL);
- if (!sctp_bucket_cachep)
- goto out;
-
- sctp_chunk_cachep = kmem_cache_create("sctp_chunk",
- sizeof(struct sctp_chunk),
- 0, SLAB_HWCACHE_ALIGN,
- NULL);
- if (!sctp_chunk_cachep)
- goto err_chunk_cachep;
-
- /* Allocate and initialise sctp mibs. */
- status = init_sctp_mibs();
- if (status)
- goto err_init_mibs;
-
- /* Initialize proc fs directory. */
- status = sctp_proc_init();
- if (status)
- goto err_init_proc;
-
- /* Initialize object count debugging. */
- sctp_dbg_objcnt_init();
-
/*
* 14. Suggested SCTP Protocol Parameter Values
*/
/* The following protocol parameters are RECOMMENDED: */
- /* RTO.Initial - 3 seconds */
- sctp_rto_initial = SCTP_RTO_INITIAL;
- /* RTO.Min - 1 second */
- sctp_rto_min = SCTP_RTO_MIN;
- /* RTO.Max - 60 seconds */
- sctp_rto_max = SCTP_RTO_MAX;
- /* RTO.Alpha - 1/8 */
- sctp_rto_alpha = SCTP_RTO_ALPHA;
- /* RTO.Beta - 1/4 */
- sctp_rto_beta = SCTP_RTO_BETA;
-
- /* Valid.Cookie.Life - 60 seconds */
- sctp_valid_cookie_life = SCTP_DEFAULT_COOKIE_LIFE;
+ /* RTO.Initial - 3 seconds */
+ sctp_rto_initial = SCTP_RTO_INITIAL;
+ /* RTO.Min - 1 second */
+ sctp_rto_min = SCTP_RTO_MIN;
+ /* RTO.Max - 60 seconds */
+ sctp_rto_max = SCTP_RTO_MAX;
+ /* RTO.Alpha - 1/8 */
+ sctp_rto_alpha = SCTP_RTO_ALPHA;
+ /* RTO.Beta - 1/4 */
+ sctp_rto_beta = SCTP_RTO_BETA;
+
+ /* Valid.Cookie.Life - 60 seconds */
+ sctp_valid_cookie_life = SCTP_DEFAULT_COOKIE_LIFE;

/* Whether Cookie Preservative is enabled(1) or not(0) */
- sctp_cookie_preserve_enable = 1;
+ sctp_cookie_preserve_enable = 1;

- /* Max.Burst - 4 */
- sctp_max_burst = SCTP_DEFAULT_MAX_BURST;
+ /* Max.Burst - 4 */
+ sctp_max_burst = SCTP_DEFAULT_MAX_BURST;

- /* Association.Max.Retrans - 10 attempts
- * Path.Max.Retrans - 5 attempts (per destination address)
- * Max.Init.Retransmits - 8 attempts
+ /* Association.Max.Retrans - 10 attempts
+ * Path.Max.Retrans - 5 attempts (per destination address)
+ * Max.Init.Retransmits - 8 attempts
*/
- sctp_max_retrans_association = 10;
- sctp_max_retrans_path = 5;
- sctp_max_retrans_init = 8;
+ sctp_max_retrans_association = 10;
+ sctp_max_retrans_path = 5;
+ sctp_max_retrans_init = 8;

- /* Sendbuffer growth - do per-socket accounting */
- sctp_sndbuf_policy = 0;
+ /* Sendbuffer growth - do per-socket accounting */
+ sctp_sndbuf_policy = 0;

- /* Rcvbuffer growth - do per-socket accounting */
- sctp_rcvbuf_policy = 0;
+ /* Rcvbuffer growth - do per-socket accounting */
+ sctp_rcvbuf_policy = 0;

- /* HB.interval - 30 seconds */
+ /* HB.interval - 30 seconds */
sctp_hb_interval = SCTP_DEFAULT_TIMEOUT_HEARTBEAT;

/* delayed SACK timeout */
- sctp_sack_timeout = SCTP_DEFAULT_TIMEOUT_SACK;
+ sctp_sack_timeout = SCTP_DEFAULT_TIMEOUT_SACK;

/* Implementation specific variables. */

/* Initialize default stream count setup information. */
- sctp_max_instreams = SCTP_DEFAULT_INSTREAMS;
- sctp_max_outstreams = SCTP_DEFAULT_OUTSTREAMS;
+ sctp_max_instreams = SCTP_DEFAULT_INSTREAMS;
+ sctp_max_outstreams = SCTP_DEFAULT_OUTSTREAMS;

/* Initialize maximum autoclose timeout. */
- sctp_max_autoclose = INT_MAX / HZ;
+ sctp_max_autoclose = INT_MAX / HZ;
+
+ /* Disable ADDIP by default. */
+ sctp_addip_enable = 0;
+ sctp_addip_noauth = 0;
+ sctp_default_auto_asconf = 0;

- /* Initialize handle used for association ids. */
- idr_init(&sctp_assocs_id);
+ /* Enable PR-SCTP by default. */
+ sctp_prsctp_enable = 1;
+
+ /* Disable AUTH by default. */
+ sctp_auth_enable = 0;

+ /* Set SCOPE policy to enabled */
+ sctp_scope_policy = SCTP_SCOPE_POLICY_ENABLE;
+
+ /* Set the default rwnd update threshold */
+ sctp_rwnd_upd_shift = SCTP_DEFAULT_RWND_SHIFT;
+ return;
+}
+
+static void sctp_memory_globals_init(void)
+{
+ unsigned long limit;
+ int max_share;
+
+ /* Set the pressure threshold to be a fraction of global memory that
+ * is up to 1/2 at 256 MB, decreasing toward zero with the amount of
+ * memory, with a floor of 128 pages.
+ * Note this initializes the data in sctpv6_prot too
+ * Unabashedly stolen from tcp_init
+ */
limit = nr_free_buffer_pages() / 8;
limit = max(limit, 128UL);
sysctl_sctp_mem[0] = limit / 4 * 3;
@@ -1310,6 +1291,14 @@ SCTP_STATIC __init int sctp_init(void)
sysctl_sctp_wmem[0] = SK_MEM_QUANTUM;
sysctl_sctp_wmem[1] = 16*1024;
sysctl_sctp_wmem[2] = max(64*1024, max_share);
+}
+
+static int sctp_hashtable_globals_init(void)
+{
+ unsigned long goal;
+ int status = -ENOMEM;
+ int order;
+ int i;

/* Size and allocate the association hash table.
* The methodology is similar to that of the tcp hash tables.
@@ -1325,11 +1314,13 @@ SCTP_STATIC __init int sctp_init(void)
do {
sctp_assoc_hashsize = (1UL << order) * PAGE_SIZE /
sizeof(struct sctp_hashbucket);
- if ((sctp_assoc_hashsize > (64 * 1024)) && order > 0)
- continue;
+ if ((sctp_assoc_hashsize > (64 * 1024)) && (order > 0))
+ continue;
sctp_assoc_hashtable = (struct sctp_hashbucket *)
- __get_free_pages(GFP_ATOMIC|__GFP_NOWARN, order);
- } while (!sctp_assoc_hashtable && --order > 0);
+ __get_free_pages(GFP_ATOMIC|__GFP_NOWARN|__GFP_ZERO,
+ order);
+ } while (!sctp_assoc_hashtable && (--order > 0));
+
if (!sctp_assoc_hashtable) {
pr_err("Failed association hash alloc\n");
status = -ENOMEM;
@@ -1358,11 +1349,12 @@ SCTP_STATIC __init int sctp_init(void)
do {
sctp_port_hashsize = (1UL << order) * PAGE_SIZE /
sizeof(struct sctp_bind_hashbucket);
- if ((sctp_port_hashsize > (64 * 1024)) && order > 0)
+ if ((sctp_port_hashsize > (64 * 1024)) && (order > 0))
continue;
sctp_port_hashtable = (struct sctp_bind_hashbucket *)
__get_free_pages(GFP_ATOMIC|__GFP_NOWARN, order);
- } while (!sctp_port_hashtable && --order > 0);
+ } while (!sctp_port_hashtable && (--order > 0));
+
if (!sctp_port_hashtable) {
pr_err("Failed bind hash alloc\n");
status = -ENOMEM;
@@ -1376,25 +1368,111 @@ SCTP_STATIC __init int sctp_init(void)
pr_info("Hash tables configured (established %d bind %d)\n",
sctp_assoc_hashsize, sctp_port_hashsize);

- /* Disable ADDIP by default. */
- sctp_addip_enable = 0;
- sctp_addip_noauth = 0;
- sctp_default_auto_asconf = 0;
+ goto out;

- /* Enable PR-SCTP by default. */
- sctp_prsctp_enable = 1;

- /* Disable AUTH by default. */
- sctp_auth_enable = 0;
+err_bhash_alloc:
+ kfree(sctp_ep_hashtable);
+err_ehash_alloc:
+ free_pages((unsigned long)sctp_assoc_hashtable,
+ get_order(sctp_assoc_hashsize *
+ sizeof(struct sctp_hashbucket)));
+err_ahash_alloc:
+ sctp_proc_exit();
+out:
+ return status;
+}

- /* Set SCOPE policy to enabled */
- sctp_scope_policy = SCTP_SCOPE_POLICY_ENABLE;
+static void sctp_hashtable_globals_free(void)
+{
+ free_pages((unsigned long)sctp_assoc_hashtable,
+ get_order(sctp_assoc_hashsize *
+ sizeof(struct sctp_hashbucket)));

- /* Set the default rwnd update threshold */
- sctp_rwnd_upd_shift = SCTP_DEFAULT_RWND_SHIFT;
+ kfree(sctp_ep_hashtable);
+
+ free_pages((unsigned long)sctp_port_hashtable,
+ get_order(sctp_port_hashsize *
+ sizeof(struct sctp_bind_hashbucket)));
+}
+
+static int sctp_kmem_cache_create(void)
+{
+ /* Allocate bind_bucket and chunk caches. */
+ sctp_bucket_cachep = kmem_cache_create("sctp_bind_bucket",
+ sizeof(struct sctp_bind_bucket),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL);
+
+ if (!sctp_bucket_cachep) {
+ pr_err("failed to allocate bucket cache\n");
+ goto err_bucket_cachep;
+ }
+ sctp_chunk_cachep = kmem_cache_create("sctp_chunk",
+ sizeof(struct sctp_chunk),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL);
+ if (!sctp_chunk_cachep) {
+ pr_err("failed to allocate chunk cache\n");
+ goto err_chunk_cachep;
+ }
+
+ return 0;
+
+err_chunk_cachep:
+ kmem_cache_destroy(sctp_bucket_cachep);
+err_bucket_cachep:
+ return -ENOBUFS;
+}
+
+static void sctp_kmem_cache_destroy(void)
+{
+ /* deallocate bind_bucket and chunk caches. */
+ kmem_cache_destroy(sctp_chunk_cachep);
+ kmem_cache_destroy(sctp_bucket_cachep);
+}
+
+/* Initialize the universe into something sensible. */
+SCTP_STATIC __init int sctp_init(void)
+{
+ int status = -EINVAL;
+
+ /* SCTP_DEBUG sanity check. */
+ if (!sctp_sanity_check())
+ goto out;
+
+ /* Allocate bind_bucket and chunk caches. */
+ status = sctp_kmem_cache_create();
+ if (status)
+ return status;
+
+ /* Initialize sockets counter */
+ if (percpu_counter_init(&sctp_sockets_allocated, 0)) {
+ status = -ENOMEM;
+ goto err_percpu_counter_init;
+ }
+
+ /* Allocate and initialise sctp mibs. */
+ status = init_sctp_mibs();
+ if (status)
+ goto err_init_mibs;
+
+ /* Initialize proc fs directory. */
+ status = sctp_proc_init();
+ if (status)
+ goto err_init_proc;
+
+ /* Initialize object count debugging. */
+ sctp_dbg_objcnt_init();
+
+ /* Initialize global parameters */
+ sctp_global_param_init();
+ sctp_memory_globals_init();
+ sctp_hashtable_globals_init();

sctp_sysctl_register();

+ /* Register the routines for different a-f handling */
INIT_LIST_HEAD(&sctp_address_families);
sctp_v4_pf_init();
sctp_v6_pf_init();
@@ -1411,8 +1489,8 @@ SCTP_STATIC __init int sctp_init(void)
sctp_addr_wq_timer.expires = 0;
setup_timer(&sctp_addr_wq_timer, sctp_addr_wq_timeout_handler, 0);

+ /* Register SCTP protocol */
status = sctp_v4_protosw_init();
-
if (status)
goto err_protosw_init;

@@ -1435,9 +1513,20 @@ SCTP_STATIC __init int sctp_init(void)
if (status)
goto err_v6_add_protocol;

+ /* Set up sysctl parameters. */
+ sctp_sysctl_register();
+
+ /* Allocate and initialise sctp mibs. */
+ status = init_sctp_mibs();
+ if (status)
+ goto err_mib_init;
+
status = 0;
-out:
- return status;
+ goto out;
+
+err_mib_init:
+ sctp_sysctl_unregister();
+ sctp_v6_del_protocol();
err_v6_add_protocol:
sctp_v4_del_protocol();
err_add_protocol:
@@ -1451,25 +1540,17 @@ err_protosw_init:
sctp_v4_pf_exit();
sctp_v6_pf_exit();
sctp_sysctl_unregister();
- free_pages((unsigned long)sctp_port_hashtable,
- get_order(sctp_port_hashsize *
- sizeof(struct sctp_bind_hashbucket)));
-err_bhash_alloc:
- kfree(sctp_ep_hashtable);
-err_ehash_alloc:
- free_pages((unsigned long)sctp_assoc_hashtable,
- get_order(sctp_assoc_hashsize *
- sizeof(struct sctp_hashbucket)));
-err_ahash_alloc:
+ sctp_hashtable_globals_free();
sctp_dbg_objcnt_exit();
sctp_proc_exit();
err_init_proc:
cleanup_sctp_mibs();
err_init_mibs:
- kmem_cache_destroy(sctp_chunk_cachep);
-err_chunk_cachep:
- kmem_cache_destroy(sctp_bucket_cachep);
- goto out;
+ percpu_counter_destroy(&sctp_sockets_allocated);
+err_percpu_counter_init:
+ sctp_kmem_cache_destroy();
+out:
+ return status;
}

/* Exit handler for the SCTP protocol. */
@@ -1500,22 +1581,15 @@ SCTP_STATIC __exit void sctp_exit(void)

sctp_sysctl_unregister();

- free_pages((unsigned long)sctp_assoc_hashtable,
- get_order(sctp_assoc_hashsize *
- sizeof(struct sctp_hashbucket)));
- kfree(sctp_ep_hashtable);
- free_pages((unsigned long)sctp_port_hashtable,
- get_order(sctp_port_hashsize *
- sizeof(struct sctp_bind_hashbucket)));
+ sctp_hashtable_globals_free();

sctp_dbg_objcnt_exit();
sctp_proc_exit();
+ percpu_counter_destroy(&sctp_sockets_allocated);
cleanup_sctp_mibs();

rcu_barrier(); /* Wait for completion of call_rcu()'s */
-
- kmem_cache_destroy(sctp_chunk_cachep);
- kmem_cache_destroy(sctp_bucket_cachep);
+ sctp_kmem_cache_destroy();
}

module_init(sctp_init);
--
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/