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