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