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