Add namespace-helper functions to access per-namespace parameters and variables. Create per-namespace control socket for out-of-the- blue packets, initialize per-namespace protocol parameters, and register SCTP protocol for namespace handling. Signed-off-by: Jan Ariyasu <jan.ariyasu@xxxxxx> --- include/net/sctp/sctp.h | 31 ++++- net/sctp/input.c | 4 +- net/sctp/protocol.c | 292 +++++++++++++++++++++++++++++++++++------------ net/sctp/sm_statefuns.c | 10 +- 4 files changed, 256 insertions(+), 81 deletions(-) diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index ff49964..c2dfeea 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -70,6 +70,8 @@ #include <linux/spinlock.h> #include <linux/jiffies.h> #include <linux/idr.h> +#include <net/net_namespace.h> +#include <net/netns/generic.h> #if IS_ENABLED(CONFIG_IPV6) #include <net/ipv6.h> @@ -107,6 +109,9 @@ #define SCTP_STATIC static #endif +/* For namespace identification */ +extern int sctp_net_id; + /* * Function declarations. */ @@ -114,7 +119,6 @@ /* * sctp/protocol.c */ -extern struct sock *sctp_get_ctl_sock(void); extern int sctp_copy_local_addr_list(struct sctp_bind_addr *, sctp_scope_t, gfp_t gfp, int flags); @@ -719,4 +723,29 @@ static inline struct dst_entry *sctp_transport_dst_check(struct sctp_transport * return t->dst; } +/* Namespace helper functions */ +static inline struct sctp_ns_globals *sctp_get_ns_globals(struct net *net) +{ + struct sctp_ns_globals *ns_globals = + (struct sctp_ns_globals *) net_generic(net, sctp_net_id); + return ns_globals; + +} + +/* Return the address of the control sock. */ +static inline struct sock **sctp_get_ctl_sock(struct net *net) +{ + struct sctp_ns_globals *ns_globals = + (struct sctp_ns_globals *) net_generic(net, sctp_net_id); + return &ns_globals->sctp_ctl_sock; +} + +/* Return the address of the protocol globals. */ +static inline struct sctp_net_params *sctp_get_params(struct net *net) +{ + struct sctp_ns_globals *ns_globals = + (struct sctp_ns_globals *) net_generic(net, sctp_net_id); + return &ns_globals->protocol_params; +} + #endif /* __net_sctp_h__ */ diff --git a/net/sctp/input.c b/net/sctp/input.c index e64d521..fc94829 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -200,7 +200,7 @@ int sctp_rcv(struct sk_buff *skb) sctp_endpoint_put(ep); ep = NULL; } - sk = sctp_get_ctl_sock(); + sk = *(sctp_get_ctl_sock(&init_net)); ep = sctp_sk(sk)->ep; sctp_endpoint_hold(ep); rcvr = &ep->base; @@ -787,7 +787,7 @@ static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *l goto hit; } - ep = sctp_sk((sctp_get_ctl_sock()))->ep; + ep = sctp_sk(*(sctp_get_ctl_sock(&init_net)))->ep; hit: sctp_endpoint_hold(ep); diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index cafdaac..5c1a18c 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -78,11 +78,11 @@ struct proc_dir_entry *proc_net_sctp; struct idr sctp_assocs_id; DEFINE_SPINLOCK(sctp_assocs_id_lock); -/* This is the global socket data structure used for responding to - * the Out-of-the-blue (OOTB) packets. A control sock will be created - * for this socket at the initialization time. +/* + * This id will allow us to access per-namespace globals in + * struct sctp_ns_globals, defined as net_generic in struct net. */ -static struct sock *sctp_ctl_sock; +int sctp_net_id __read_mostly; static struct sctp_pf *sctp_pf_inet6_specific; static struct sctp_pf *sctp_pf_inet_specific; @@ -96,32 +96,33 @@ long sysctl_sctp_mem[3]; int sysctl_sctp_rmem[3]; int sysctl_sctp_wmem[3]; -/* Return the address of the control sock. */ -struct sock *sctp_get_ctl_sock(void) -{ - return sctp_ctl_sock; -} - /* Set up the proc fs entry for the SCTP protocol. */ static __init int sctp_proc_init(void) { #ifdef CONFIG_PROC_FS + int status = 0; if (!proc_net_sctp) { proc_net_sctp = proc_mkdir("sctp", init_net.proc_net); - if (!proc_net_sctp) - goto out_nomem; + if (!proc_net_sctp) { + status = -ENOMEM; + goto out; + } } - if (sctp_snmp_proc_init()) + status = sctp_snmp_proc_init(); + if (status) goto out_snmp_proc_init; - if (sctp_eps_proc_init()) + status = sctp_eps_proc_init(); + if (status) goto out_eps_proc_init; - if (sctp_assocs_proc_init()) + status = sctp_assocs_proc_init(); + if (status) goto out_assocs_proc_init; - if (sctp_remaddr_proc_init()) + status = sctp_remaddr_proc_init(); + if (status) goto out_remaddr_proc_init; - return 0; + return status; out_remaddr_proc_init: sctp_assocs_proc_exit(); @@ -134,9 +135,8 @@ out_snmp_proc_init: proc_net_sctp = NULL; remove_proc_entry("sctp", init_net.proc_net); } - -out_nomem: - return -ENOMEM; +out: + return status; #else return 0; #endif /* CONFIG_PROC_FS */ @@ -817,22 +817,23 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev, * Initialize the control inode/socket with a control endpoint data * structure. This endpoint is reserved exclusively for the OOTB processing. */ -static int sctp_ctl_sock_init(void) +static int sctp_ctl_sock_init(struct net *net) { int err; sa_family_t family = PF_INET; + struct sock **ctl_sock = sctp_get_ctl_sock(net); if (sctp_get_pf_specific(PF_INET6)) family = PF_INET6; - err = inet_ctl_sock_create(&sctp_ctl_sock, family, - SOCK_SEQPACKET, IPPROTO_SCTP, &init_net); + err = inet_ctl_sock_create(ctl_sock, family, + SOCK_SEQPACKET, IPPROTO_SCTP, net); /* If IPv6 socket could not be created, try the IPv4 socket */ if (err < 0 && family == PF_INET6) - err = inet_ctl_sock_create(&sctp_ctl_sock, AF_INET, + err = inet_ctl_sock_create(ctl_sock, AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP, - &init_net); + net); if (err < 0) { pr_err("Failed to create the SCTP control socket\n"); @@ -841,6 +842,12 @@ static int sctp_ctl_sock_init(void) return 0; } +static inline void sctp_ctl_sock_destroy(struct net *net) +{ + struct sock **sctp_ctl_sk = sctp_get_ctl_sock(net); + inet_ctl_sock_destroy(*sctp_ctl_sk); +} + /* Register address family specific functions. */ int sctp_register_af(struct sctp_af *af) { @@ -1151,17 +1158,18 @@ static void sctp_v4_pf_exit(void) static int sctp_v4_protosw_init(void) { - int rc; - + int rc = 0; rc = proto_register(&sctp_prot, 1); - if (rc) + if (rc) { + pr_err("Failed to register SCTP protocol\n"); return rc; + } /* Register SCTP(UDP and TCP style) with socket layer. */ inet_register_protosw(&sctp_seqpacket_protosw); inet_register_protosw(&sctp_stream_protosw); - return 0; + return rc; } static void sctp_v4_protosw_exit(void) @@ -1219,8 +1227,8 @@ static void sctp_global_param_init(void) * 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_association = 10; + sctp_max_retrans_path = 5; sctp_max_retrans_init = 8; /* Sendbuffer growth - do per-socket accounting */ @@ -1238,8 +1246,8 @@ static void sctp_global_param_init(void) /* 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; @@ -1263,6 +1271,112 @@ static void sctp_global_param_init(void) return; } + +static int sctp_net_param_init(struct net *net) +{ + struct sctp_net_params *net_params = sctp_get_params(net); + struct sctp_ns_globals *ns_globals = sctp_get_ns_globals(net); + if ((net_params == NULL) || (ns_globals == NULL)) + return -ENOMEM; + + /* Initialize SCTP protocol parameters + * 14. Suggested SCTP Protocol Parameter Values + */ + /* The following protocol parameters are RECOMMENDED: */ + /* RTO.Initial - 3 seconds */ + net_params->rto_initial = SCTP_RTO_INITIAL; + /* RTO.Min - 1 second */ + net_params->rto_min = SCTP_RTO_MIN; + /* RTO.Max - 60 seconds */ + net_params->rto_max = SCTP_RTO_MAX; + /* RTO.Alpha - 1/8 */ + net_params->rto_alpha = SCTP_RTO_ALPHA; + /* RTO.Beta - 1/4 */ + net_params->rto_beta = SCTP_RTO_BETA; + + /* Max.Burst - 4 */ + net_params->max_burst = SCTP_DEFAULT_MAX_BURST; + + /* Whether Cookie Preservative is enabled(1) or not(0) */ + net_params->cookie_preserve_enable = 1; + + /* Valid.Cookie.Life - 60 seconds */ + net_params->valid_cookie_life = SCTP_DEFAULT_COOKIE_LIFE; + + /* delayed SACK timeout */ + net_params->sack_timeout = SCTP_DEFAULT_TIMEOUT_SACK; + + /* HB.interval - 30 seconds */ + net_params->hb_interval = SCTP_DEFAULT_TIMEOUT_HEARTBEAT; + + /* Association.Max.Retrans - 10 attempts + * Path.Max.Retrans - 5 attempts (per destination address) + * Max.Init.Retransmits - 8 attempts + */ + net_params->max_retrans_association = 10; + net_params->max_retrans_path = 5; + net_params->max_retrans_init = 8; + + /* Sendbuffer growth - do per-socket accounting */ + net_params->sndbuf_policy = 0; + + /* Rcvbuffer growth - do per-socket accounting */ + net_params->rcvbuf_policy = 0; + + /* Implementation specific variables. */ + + /* Initialize default stream count setup information. */ + net_params->max_instreams = SCTP_DEFAULT_INSTREAMS; + net_params->max_outstreams = SCTP_DEFAULT_OUTSTREAMS; + + /* hash of all endpoints */ + net_params->ep_hashsize = 64; + net_params->ep_hashtable = NULL; + + /* hash of all associations */ + net_params->assoc_hashsize = 0; + net_params->assoc_hashtable = NULL; + + /* port-control hash */ + net_params->port_hashsize = 0; + net_params->port_hashtable = NULL; + + /* Initialize local address list */ + INIT_LIST_HEAD(&net_params->local_addr_list); + spin_lock_init(&net_params->addr_list_lock); + idr_init(&ns_globals->assocs_id); + spin_lock_init(&ns_globals->assocs_id_lock); + + /* Disable ADDIP by default. */ + net_params->addip_enable = 0; + net_params->addip_noauth_enable = 0; + net_params->default_auto_asconf = 0; + + /* Set SCOPE policy to enabled */ + net_params->ipv4_scope_policy = SCTP_SCOPE_POLICY_ENABLE; + + /* Set the default rwnd update threshold */ + net_params->rwnd_update_shift = SCTP_DEFAULT_RWND_SHIFT; + + /* Enable PR-SCTP by default. */ + net_params->prsctp_enable = 1; + + /* Disable AUTH by default. */ + net_params->auth_enable = 0; + + /* Initialize maximum autoclose timeout. */ + net_params->max_autoclose = INT_MAX / HZ; + + /* Initialize address event list */ + INIT_LIST_HEAD(&net_params->addr_waitq); + net_params->addr_wq_timer.expires = 0; + INIT_LIST_HEAD(&net_params->auto_asconf_splist); + spin_lock_init(&net_params->addr_wq_lock); + setup_timer(&net_params->addr_wq_timer, sctp_addr_wq_timeout_handler, + (unsigned long)net); + return 0; +} + static void sctp_memory_globals_init(void) { unsigned long limit; @@ -1318,13 +1432,13 @@ static int sctp_hashtable_globals_init(void) continue; sctp_assoc_hashtable = (struct sctp_hashbucket *) __get_free_pages(GFP_ATOMIC|__GFP_NOWARN|__GFP_ZERO, - order); + order); } while (!sctp_assoc_hashtable && (--order > 0)); if (!sctp_assoc_hashtable) { pr_err("Failed association hash alloc\n"); status = -ENOMEM; - goto err_ahash_alloc; + goto out; } for (i = 0; i < sctp_assoc_hashsize; i++) { rwlock_init(&sctp_assoc_hashtable[i].lock); @@ -1377,8 +1491,6 @@ 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; } @@ -1432,6 +1544,49 @@ static void sctp_kmem_cache_destroy(void) kmem_cache_destroy(sctp_bucket_cachep); } +/* namespace enablers for init */ + +static int __net_init sctp_net_init(struct net *net) +{ + int err = 0; + + /* Set up the control socket for OOTB packets */ + err = sctp_ctl_sock_init(net); + if (err) + goto out; + + err = sctp_net_param_init(net); + if (err) + goto err_param_init; + +err_param_init: + sctp_ctl_sock_destroy(net); +out: + return err; +} + +static void __net_exit sctp_net_exit(struct net *net) +{ + sctp_ctl_sock_destroy(net); +} + +static __net_initdata struct pernet_operations sctp_sk_ops = { + .init = sctp_net_init, + .exit = sctp_net_exit, + .id = &sctp_net_id, + .size = sizeof(struct sctp_ns_globals), +}; + +static int __net_init sctp_ns_init(void) +{ + return register_pernet_subsys(&sctp_sk_ops); +} + +static void __net_exit sctp_ns_exit(void) +{ + unregister_pernet_subsys(&sctp_sk_ops); +} + /* Initialize the universe into something sensible. */ SCTP_STATIC __init int sctp_init(void) { @@ -1452,26 +1607,11 @@ SCTP_STATIC __init int sctp_init(void) 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(); @@ -1498,22 +1638,32 @@ SCTP_STATIC __init int sctp_init(void) if (status) goto err_v6_protosw_init; - /* Initialize the control inode/socket for handling OOTB packets. */ - if ((status = sctp_ctl_sock_init())) { - pr_err("Failed to initialize the SCTP control sock\n"); - goto err_ctl_sock_init; - } - status = sctp_v4_add_protocol(); if (status) goto err_add_protocol; - /* Register SCTP with inet6 layer. */ status = sctp_v6_add_protocol(); if (status) goto err_v6_add_protocol; - /* Set up sysctl parameters. */ + /* + * Register for pernet packet handling + */ + status = sctp_ns_init(); + if (status) { + pr_err("Failed to register SCTP for namespaces\n"); + goto err_ns_init; + } + + /* Initialize proc fs directory. */ + status = sctp_proc_init(); + if (status) + goto err_init_proc; + + /* Initialize object count debugging. */ + sctp_dbg_objcnt_init(); + + /* Set up sysctl parameters. */ sctp_sysctl_register(); /* Allocate and initialise sctp mibs. */ @@ -1526,26 +1676,23 @@ SCTP_STATIC __init int sctp_init(void) err_mib_init: sctp_sysctl_unregister(); + sctp_dbg_objcnt_exit(); + sctp_proc_exit(); +err_init_proc: + sctp_ns_exit(); +err_ns_init: sctp_v6_del_protocol(); err_v6_add_protocol: sctp_v4_del_protocol(); err_add_protocol: - inet_ctl_sock_destroy(sctp_ctl_sock); -err_ctl_sock_init: sctp_v6_protosw_exit(); err_v6_protosw_init: sctp_v4_protosw_exit(); err_protosw_init: sctp_free_local_addr_list(); - sctp_v4_pf_exit(); sctp_v6_pf_exit(); - sctp_sysctl_unregister(); + sctp_v4_pf_exit(); sctp_hashtable_globals_free(); - sctp_dbg_objcnt_exit(); - sctp_proc_exit(); -err_init_proc: - cleanup_sctp_mibs(); -err_init_mibs: percpu_counter_destroy(&sctp_sockets_allocated); err_percpu_counter_init: sctp_kmem_cache_destroy(); @@ -1565,9 +1712,6 @@ SCTP_STATIC __exit void sctp_exit(void) sctp_v4_del_protocol(); sctp_free_addr_wq(); - /* Free the control endpoint. */ - inet_ctl_sock_destroy(sctp_ctl_sock); - /* Free protosw registrations */ sctp_v6_protosw_exit(); sctp_v4_protosw_exit(); @@ -1580,7 +1724,6 @@ SCTP_STATIC __exit void sctp_exit(void) sctp_v4_pf_exit(); sctp_sysctl_unregister(); - sctp_hashtable_globals_free(); sctp_dbg_objcnt_exit(); @@ -1588,6 +1731,9 @@ SCTP_STATIC __exit void sctp_exit(void) percpu_counter_destroy(&sctp_sockets_allocated); cleanup_sctp_mibs(); + /* Unregister from namespaces */ + sctp_ns_exit(); + rcu_barrier(); /* Wait for completion of call_rcu()'s */ sctp_kmem_cache_destroy(); } diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 9fca103..91dcdd6 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -318,7 +318,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep, /* If the packet is an OOTB packet which is temporarily on the * control endpoint, respond with an ABORT. */ - if (ep == sctp_sk((sctp_get_ctl_sock()))->ep) { + if (ep == sctp_sk((*(sctp_get_ctl_sock(&init_net))))->ep) { SCTP_INC_STATS(SCTP_MIB_OUTOFBLUES); return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands); } @@ -650,7 +650,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, /* If the packet is an OOTB packet which is temporarily on the * control endpoint, respond with an ABORT. */ - if (ep == sctp_sk((sctp_get_ctl_sock()))->ep) { + if (ep == sctp_sk((*(sctp_get_ctl_sock(&init_net))))->ep) { SCTP_INC_STATS(SCTP_MIB_OUTOFBLUES); return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands); } @@ -1197,7 +1197,7 @@ static int sctp_sf_send_restart_abort(union sctp_addr *ssa, errhdr->length = htons(len); /* Assign to the control socket. */ - ep = sctp_sk((sctp_get_ctl_sock()))->ep; + ep = sctp_sk(*(sctp_get_ctl_sock(&init_net)))->ep; /* Association is NULL since this may be a restart attack and we * want to send back the attacker's vtag. @@ -1653,7 +1653,7 @@ sctp_disposition_t sctp_sf_do_5_2_3_initack(const struct sctp_endpoint *ep, /* Per the above section, we'll discard the chunk if we have an * endpoint. If this is an OOTB INIT-ACK, treat it as such. */ - if (ep == sctp_sk((sctp_get_ctl_sock()))->ep) + if (ep == sctp_sk(*(sctp_get_ctl_sock(&init_net)))->ep) return sctp_sf_ootb(ep, asoc, type, arg, commands); else return sctp_sf_discard_chunk(ep, asoc, type, arg, commands); @@ -5919,7 +5919,7 @@ static struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc * the source address. */ sctp_transport_route(transport, (union sctp_addr *)&chunk->dest, - sctp_sk(sctp_get_ctl_sock())); + sctp_sk(*sctp_get_ctl_sock(&init_net))); packet = sctp_packet_init(&transport->packet, transport, sport, dport); packet = sctp_packet_config(packet, vtag, 0); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-sctp" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html