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 * 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 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 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 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 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 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 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