xref: /titanic_50/usr/src/uts/common/inet/sctp/sctp_misc.c (revision 6a634c9dca3093f3922e4b7ab826d7bdf17bf78e)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 #include <sys/types.h>
27 #include <inet/common.h>
28 #include "sctp_impl.h"
29 
30 /* Control whether SCTP can enter defensive mode when under memory pressure. */
31 static boolean_t sctp_do_reclaim = B_TRUE;
32 
33 static void	sctp_reclaim_timer(void *);
34 
35 /* Diagnostic routine used to return a string associated with the sctp state. */
36 char *
sctp_display(sctp_t * sctp,char * sup_buf)37 sctp_display(sctp_t *sctp, char *sup_buf)
38 {
39 	char	*buf;
40 	char	buf1[30];
41 	static char	priv_buf[INET6_ADDRSTRLEN * 2 + 80];
42 	char	*cp;
43 	conn_t	*connp;
44 
45 	if (sctp == NULL)
46 		return ("NULL_SCTP");
47 
48 	connp = sctp->sctp_connp;
49 	buf = (sup_buf != NULL) ? sup_buf : priv_buf;
50 
51 	switch (sctp->sctp_state) {
52 	case SCTPS_IDLE:
53 		cp = "SCTP_IDLE";
54 		break;
55 	case SCTPS_BOUND:
56 		cp = "SCTP_BOUND";
57 		break;
58 	case SCTPS_LISTEN:
59 		cp = "SCTP_LISTEN";
60 		break;
61 	case SCTPS_COOKIE_WAIT:
62 		cp = "SCTP_COOKIE_WAIT";
63 		break;
64 	case SCTPS_COOKIE_ECHOED:
65 		cp = "SCTP_COOKIE_ECHOED";
66 		break;
67 	case SCTPS_ESTABLISHED:
68 		cp = "SCTP_ESTABLISHED";
69 		break;
70 	case SCTPS_SHUTDOWN_PENDING:
71 		cp = "SCTP_SHUTDOWN_PENDING";
72 		break;
73 	case SCTPS_SHUTDOWN_SENT:
74 		cp = "SCTPS_SHUTDOWN_SENT";
75 		break;
76 	case SCTPS_SHUTDOWN_RECEIVED:
77 		cp = "SCTPS_SHUTDOWN_RECEIVED";
78 		break;
79 	case SCTPS_SHUTDOWN_ACK_SENT:
80 		cp = "SCTPS_SHUTDOWN_ACK_SENT";
81 		break;
82 	default:
83 		(void) mi_sprintf(buf1, "SCTPUnkState(%d)", sctp->sctp_state);
84 		cp = buf1;
85 		break;
86 	}
87 	(void) mi_sprintf(buf, "[%u, %u] %s",
88 	    ntohs(connp->conn_lport), ntohs(connp->conn_fport), cp);
89 
90 	return (buf);
91 }
92 
93 void
sctp_display_all(sctp_stack_t * sctps)94 sctp_display_all(sctp_stack_t *sctps)
95 {
96 	sctp_t *sctp_walker;
97 
98 	mutex_enter(&sctps->sctps_g_lock);
99 	for (sctp_walker = list_head(&sctps->sctps_g_list);
100 	    sctp_walker != NULL;
101 	    sctp_walker = (sctp_t *)list_next(&sctps->sctps_g_list,
102 	    sctp_walker)) {
103 		(void) sctp_display(sctp_walker, NULL);
104 	}
105 	mutex_exit(&sctps->sctps_g_lock);
106 }
107 
108 /*
109  * Given a sctp_stack_t and a port (in host byte order), find a listener
110  * configuration for that port and return the ratio.
111  */
112 uint32_t
sctp_find_listener_conf(sctp_stack_t * sctps,in_port_t port)113 sctp_find_listener_conf(sctp_stack_t *sctps, in_port_t port)
114 {
115 	sctp_listener_t	*sl;
116 	uint32_t ratio = 0;
117 
118 	mutex_enter(&sctps->sctps_listener_conf_lock);
119 	for (sl = list_head(&sctps->sctps_listener_conf); sl != NULL;
120 	    sl = list_next(&sctps->sctps_listener_conf, sl)) {
121 		if (sl->sl_port == port) {
122 			ratio = sl->sl_ratio;
123 			break;
124 		}
125 	}
126 	mutex_exit(&sctps->sctps_listener_conf_lock);
127 	return (ratio);
128 }
129 
130 /*
131  * To remove all listener limit configuration in a sctp_stack_t.
132  */
133 void
sctp_listener_conf_cleanup(sctp_stack_t * sctps)134 sctp_listener_conf_cleanup(sctp_stack_t *sctps)
135 {
136 	sctp_listener_t	*sl;
137 
138 	mutex_enter(&sctps->sctps_listener_conf_lock);
139 	while ((sl = list_head(&sctps->sctps_listener_conf)) != NULL) {
140 		list_remove(&sctps->sctps_listener_conf, sl);
141 		kmem_free(sl, sizeof (sctp_listener_t));
142 	}
143 	mutex_destroy(&sctps->sctps_listener_conf_lock);
144 	list_destroy(&sctps->sctps_listener_conf);
145 }
146 
147 
148 /*
149  * Timeout function to reset the SCTP stack variable sctps_reclaim to false.
150  */
151 static void
sctp_reclaim_timer(void * arg)152 sctp_reclaim_timer(void *arg)
153 {
154 	sctp_stack_t *sctps = (sctp_stack_t *)arg;
155 	int64_t tot_assoc = 0;
156 	int i;
157 	extern pgcnt_t lotsfree, needfree;
158 
159 	for (i = 0; i < sctps->sctps_sc_cnt; i++)
160 		tot_assoc += sctps->sctps_sc[i]->sctp_sc_assoc_cnt;
161 
162 	/*
163 	 * This happens only when a stack is going away.  sctps_reclaim_tid
164 	 * should not be reset to 0 when returning in this case.
165 	 */
166 	mutex_enter(&sctps->sctps_reclaim_lock);
167 	if (!sctps->sctps_reclaim) {
168 		mutex_exit(&sctps->sctps_reclaim_lock);
169 		return;
170 	}
171 
172 	if ((freemem >= lotsfree + needfree) || tot_assoc < maxusers) {
173 		sctps->sctps_reclaim = B_FALSE;
174 		sctps->sctps_reclaim_tid = 0;
175 	} else {
176 		/* Stay in defensive mode and restart the timer */
177 		sctps->sctps_reclaim_tid = timeout(sctp_reclaim_timer,
178 		    sctps, MSEC_TO_TICK(sctps->sctps_reclaim_period));
179 	}
180 	mutex_exit(&sctps->sctps_reclaim_lock);
181 }
182 
183 /*
184  * Kmem reclaim call back function.  When the system is under memory
185  * pressure, we set the SCTP stack variable sctps_reclaim to true.  This
186  * variable is reset to false after sctps_reclaim_period msecs.  During this
187  * period, SCTP will be more aggressive in aborting connections not making
188  * progress, meaning retransmitting for shorter time (sctp_pa_early_abort/
189  * sctp_pp_early_abort number of strikes).
190  */
191 /* ARGSUSED */
192 void
sctp_conn_reclaim(void * arg)193 sctp_conn_reclaim(void *arg)
194 {
195 	netstack_handle_t nh;
196 	netstack_t *ns;
197 	sctp_stack_t *sctps;
198 	extern pgcnt_t lotsfree, needfree;
199 
200 	if (!sctp_do_reclaim)
201 		return;
202 
203 	/*
204 	 * The reclaim function may be called even when the system is not
205 	 * really under memory pressure.
206 	 */
207 	if (freemem >= lotsfree + needfree)
208 		return;
209 
210 	netstack_next_init(&nh);
211 	while ((ns = netstack_next(&nh)) != NULL) {
212 		int i;
213 		int64_t tot_assoc = 0;
214 
215 		/*
216 		 * During boot time, the first netstack_t is created and
217 		 * initialized before SCTP has registered with the netstack
218 		 * framework.  If this reclaim function is called before SCTP
219 		 * has finished its initialization, netstack_next() will
220 		 * return the first netstack_t (since its netstack_flags is
221 		 * not NSF_UNINIT).  And its netstack_sctp will be NULL.  We
222 		 * need to catch it.
223 		 *
224 		 * All subsequent netstack_t creation will not have this
225 		 * problem since the initialization is not finished until SCTP
226 		 * has finished its own sctp_stack_t initialization.  Hence
227 		 * netstack_next() will not return one with NULL netstack_sctp.
228 		 */
229 		if ((sctps = ns->netstack_sctp) == NULL) {
230 			netstack_rele(ns);
231 			continue;
232 		}
233 
234 		/*
235 		 * Even if the system is under memory pressure, the reason may
236 		 * not be because of SCTP activity.  Check the number of
237 		 * associations in each stack.  If the number exceeds the
238 		 * threshold (maxusers), turn on defensive mode.
239 		 */
240 		for (i = 0; i < sctps->sctps_sc_cnt; i++)
241 			tot_assoc += sctps->sctps_sc[i]->sctp_sc_assoc_cnt;
242 		if (tot_assoc < maxusers) {
243 			netstack_rele(ns);
244 			continue;
245 		}
246 
247 		mutex_enter(&sctps->sctps_reclaim_lock);
248 		if (!sctps->sctps_reclaim) {
249 			sctps->sctps_reclaim = B_TRUE;
250 			sctps->sctps_reclaim_tid = timeout(sctp_reclaim_timer,
251 			    sctps, MSEC_TO_TICK(sctps->sctps_reclaim_period));
252 			SCTP_KSTAT(sctps, sctp_reclaim_cnt);
253 		}
254 		mutex_exit(&sctps->sctps_reclaim_lock);
255 		netstack_rele(ns);
256 	}
257 	netstack_next_fini(&nh);
258 }
259 
260 /*
261  * When a CPU is added, we need to allocate the per CPU stats struct.
262  */
263 void
sctp_stack_cpu_add(sctp_stack_t * sctps,processorid_t cpu_seqid)264 sctp_stack_cpu_add(sctp_stack_t *sctps, processorid_t cpu_seqid)
265 {
266 	int i;
267 
268 	if (cpu_seqid < sctps->sctps_sc_cnt)
269 		return;
270 	for (i = sctps->sctps_sc_cnt; i <= cpu_seqid; i++) {
271 		ASSERT(sctps->sctps_sc[i] == NULL);
272 		sctps->sctps_sc[i] = kmem_zalloc(sizeof (sctp_stats_cpu_t),
273 		    KM_SLEEP);
274 	}
275 	membar_producer();
276 	sctps->sctps_sc_cnt = cpu_seqid + 1;
277 }
278