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) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #include <inet/ip.h> 27 #include <inet/ip6.h> 28 #include <inet/sctp/sctp_stack.h> 29 #include <inet/sctp/sctp_impl.h> 30 #include <sys/sunddi.h> 31 32 /* Max size IP datagram is 64k - 1 */ 33 #define SCTP_MSS_MAX_IPV4 (IP_MAXPACKET - (sizeof (ipha_t) + \ 34 sizeof (sctp_hdr_t))) 35 #define SCTP_MSS_MAX_IPV6 (IP_MAXPACKET - (sizeof (ip6_t) + \ 36 sizeof (sctp_hdr_t))) 37 /* Max of the above */ 38 #define SCTP_MSS_MAX SCTP_MSS_MAX_IPV4 39 40 /* 41 * returns the current list of listener limit configuration. 42 */ 43 /* ARGSUSED */ 44 static int 45 sctp_listener_conf_get(void *cbarg, mod_prop_info_t *pinfo, const char *ifname, 46 void *val, uint_t psize, uint_t flags) 47 { 48 sctp_stack_t *sctps = (sctp_stack_t *)cbarg; 49 sctp_listener_t *sl; 50 char *pval = val; 51 size_t nbytes = 0, tbytes = 0; 52 uint_t size; 53 int err = 0; 54 55 bzero(pval, psize); 56 size = psize; 57 58 if (flags & (MOD_PROP_DEFAULT|MOD_PROP_PERM|MOD_PROP_POSSIBLE)) 59 return (0); 60 61 mutex_enter(&sctps->sctps_listener_conf_lock); 62 for (sl = list_head(&sctps->sctps_listener_conf); sl != NULL; 63 sl = list_next(&sctps->sctps_listener_conf, sl)) { 64 if (psize == size) 65 nbytes = snprintf(pval, size, "%d:%d", sl->sl_port, 66 sl->sl_ratio); 67 else 68 nbytes = snprintf(pval, size, ",%d:%d", sl->sl_port, 69 sl->sl_ratio); 70 size -= nbytes; 71 pval += nbytes; 72 tbytes += nbytes; 73 if (tbytes >= psize) { 74 /* Buffer overflow, stop copying information */ 75 err = ENOBUFS; 76 break; 77 } 78 } 79 80 mutex_exit(&sctps->sctps_listener_conf_lock); 81 return (err); 82 } 83 84 /* 85 * add a new listener limit configuration. 86 */ 87 /* ARGSUSED */ 88 static int 89 sctp_listener_conf_add(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo, 90 const char *ifname, const void* pval, uint_t flags) 91 { 92 sctp_listener_t *new_sl; 93 sctp_listener_t *sl; 94 long lport; 95 long ratio; 96 char *colon; 97 sctp_stack_t *sctps = (sctp_stack_t *)cbarg; 98 99 if (flags & MOD_PROP_DEFAULT) 100 return (ENOTSUP); 101 102 if (ddi_strtol(pval, &colon, 10, &lport) != 0 || lport <= 0 || 103 lport > USHRT_MAX || *colon != ':') { 104 return (EINVAL); 105 } 106 if (ddi_strtol(colon + 1, NULL, 10, &ratio) != 0 || ratio <= 0) 107 return (EINVAL); 108 109 mutex_enter(&sctps->sctps_listener_conf_lock); 110 for (sl = list_head(&sctps->sctps_listener_conf); sl != NULL; 111 sl = list_next(&sctps->sctps_listener_conf, sl)) { 112 /* There is an existing entry, so update its ratio value. */ 113 if (sl->sl_port == lport) { 114 sl->sl_ratio = ratio; 115 mutex_exit(&sctps->sctps_listener_conf_lock); 116 return (0); 117 } 118 } 119 120 if ((new_sl = kmem_alloc(sizeof (sctp_listener_t), KM_NOSLEEP)) == 121 NULL) { 122 mutex_exit(&sctps->sctps_listener_conf_lock); 123 return (ENOMEM); 124 } 125 126 new_sl->sl_port = lport; 127 new_sl->sl_ratio = ratio; 128 list_insert_tail(&sctps->sctps_listener_conf, new_sl); 129 mutex_exit(&sctps->sctps_listener_conf_lock); 130 return (0); 131 } 132 133 /* 134 * remove a listener limit configuration. 135 */ 136 /* ARGSUSED */ 137 static int 138 sctp_listener_conf_del(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo, 139 const char *ifname, const void* pval, uint_t flags) 140 { 141 sctp_listener_t *sl; 142 long lport; 143 sctp_stack_t *sctps = (sctp_stack_t *)cbarg; 144 145 if (flags & MOD_PROP_DEFAULT) 146 return (ENOTSUP); 147 148 if (ddi_strtol(pval, NULL, 10, &lport) != 0 || lport <= 0 || 149 lport > USHRT_MAX) { 150 return (EINVAL); 151 } 152 mutex_enter(&sctps->sctps_listener_conf_lock); 153 for (sl = list_head(&sctps->sctps_listener_conf); sl != NULL; 154 sl = list_next(&sctps->sctps_listener_conf, sl)) { 155 if (sl->sl_port == lport) { 156 list_remove(&sctps->sctps_listener_conf, sl); 157 mutex_exit(&sctps->sctps_listener_conf_lock); 158 kmem_free(sl, sizeof (sctp_listener_t)); 159 return (0); 160 } 161 } 162 mutex_exit(&sctps->sctps_listener_conf_lock); 163 return (ESRCH); 164 } 165 166 /* 167 * All of these are alterable, within the min/max values given, at run time. 168 * 169 * Note: All those tunables which do not start with "_" are Committed and 170 * therefore are public. See PSARC 2010/080. 171 */ 172 mod_prop_info_t sctp_propinfo_tbl[] = { 173 { "_max_init_retr", MOD_PROTO_SCTP, 174 mod_set_uint32, mod_get_uint32, 175 {0, 128, 8}, {8} }, 176 177 { "_pa_max_retr", MOD_PROTO_SCTP, 178 mod_set_uint32, mod_get_uint32, 179 {1, 128, 10}, {10} }, 180 181 { "_pp_max_retr", MOD_PROTO_SCTP, 182 mod_set_uint32, mod_get_uint32, 183 {1, 128, 5}, {5} }, 184 185 { "_cwnd_max", MOD_PROTO_SCTP, 186 mod_set_uint32, mod_get_uint32, 187 {128, (1<<30), 1024*1024}, {1024*1024} }, 188 189 { "smallest_nonpriv_port", MOD_PROTO_SCTP, 190 mod_set_uint32, mod_get_uint32, 191 {1024, (32*1024), 1024}, {1024} }, 192 193 { "_ipv4_ttl", MOD_PROTO_SCTP, 194 mod_set_uint32, mod_get_uint32, 195 {1, 255, 64}, {64} }, 196 197 { "_heartbeat_interval", MOD_PROTO_SCTP, 198 mod_set_uint32, mod_get_uint32, 199 {0, 1*DAYS, 30*SECONDS}, {30*SECONDS} }, 200 201 { "_initial_mtu", MOD_PROTO_SCTP, 202 mod_set_uint32, mod_get_uint32, 203 {68, 65535, 1500}, {1500} }, 204 205 { "_mtu_probe_interval", MOD_PROTO_SCTP, 206 mod_set_uint32, mod_get_uint32, 207 {0, 1*DAYS, 10*MINUTES}, {10*MINUTES} }, 208 209 { "_new_secret_interval", MOD_PROTO_SCTP, 210 mod_set_uint32, mod_get_uint32, 211 {0, 1*DAYS, 2*MINUTES}, {2*MINUTES} }, 212 213 /* tunable - 10 */ 214 { "_deferred_ack_interval", MOD_PROTO_SCTP, 215 mod_set_uint32, mod_get_uint32, 216 {10*MS, 1*MINUTES, 100*MS}, {100*MS} }, 217 218 { "_snd_lowat_fraction", MOD_PROTO_SCTP, 219 mod_set_uint32, mod_get_uint32, 220 {0, 16, 0}, {0} }, 221 222 { "_ignore_path_mtu", MOD_PROTO_SCTP, 223 mod_set_boolean, mod_get_boolean, 224 {B_FALSE}, {B_FALSE} }, 225 226 { "_initial_ssthresh", MOD_PROTO_SCTP, 227 mod_set_uint32, mod_get_uint32, 228 {1024, UINT32_MAX, SCTP_RECV_HIWATER}, { SCTP_RECV_HIWATER} }, 229 230 { "smallest_anon_port", MOD_PROTO_SCTP, 231 mod_set_uint32, mod_get_uint32, 232 {1024, ULP_MAX_PORT, 32*1024}, {32*1024} }, 233 234 { "largest_anon_port", MOD_PROTO_SCTP, 235 mod_set_uint32, mod_get_uint32, 236 {1024, ULP_MAX_PORT, ULP_MAX_PORT}, {ULP_MAX_PORT} }, 237 238 { "send_maxbuf", MOD_PROTO_SCTP, 239 mod_set_uint32, mod_get_uint32, 240 {SCTP_XMIT_LOWATER, (1<<30), SCTP_XMIT_HIWATER}, 241 {SCTP_XMIT_HIWATER} }, 242 243 { "_xmit_lowat", MOD_PROTO_SCTP, 244 mod_set_uint32, mod_get_uint32, 245 {SCTP_XMIT_LOWATER, (1<<30), SCTP_XMIT_LOWATER}, 246 {SCTP_XMIT_LOWATER} }, 247 248 { "recv_maxbuf", MOD_PROTO_SCTP, 249 mod_set_uint32, mod_get_uint32, 250 {SCTP_RECV_LOWATER, (1<<30), SCTP_RECV_HIWATER}, 251 {SCTP_RECV_HIWATER} }, 252 253 { "_max_buf", MOD_PROTO_SCTP, 254 mod_set_uint32, mod_get_uint32, 255 {8192, (1<<30), 1024*1024}, {1024*1024} }, 256 257 /* tunable - 20 */ 258 { "_rtt_updates", MOD_PROTO_SCTP, 259 mod_set_uint32, mod_get_uint32, 260 {0, 65536, 20}, {20} }, 261 262 { "_ipv6_hoplimit", MOD_PROTO_SCTP, 263 mod_set_uint32, mod_get_uint32, 264 {0, IPV6_MAX_HOPS, IPV6_DEFAULT_HOPS}, {IPV6_DEFAULT_HOPS} }, 265 266 { "_rto_min", MOD_PROTO_SCTP, 267 mod_set_uint32, mod_get_uint32, 268 {500*MS, 60*SECONDS, 1*SECONDS}, {1*SECONDS} }, 269 270 { "_rto_max", MOD_PROTO_SCTP, 271 mod_set_uint32, mod_get_uint32, 272 {1*SECONDS, 60000*SECONDS, 60*SECONDS}, {60*SECONDS} }, 273 274 { "_rto_initial", MOD_PROTO_SCTP, 275 mod_set_uint32, mod_get_uint32, 276 {1*SECONDS, 60000*SECONDS, 3*SECONDS}, {3*SECONDS} }, 277 278 { "_cookie_life", MOD_PROTO_SCTP, 279 mod_set_uint32, mod_get_uint32, 280 {10*MS, 60000*SECONDS, 60*SECONDS}, {60*SECONDS} }, 281 282 { "_max_in_streams", MOD_PROTO_SCTP, 283 mod_set_uint32, mod_get_uint32, 284 {1, UINT16_MAX, 32}, {32} }, 285 286 { "_initial_out_streams", MOD_PROTO_SCTP, 287 mod_set_uint32, mod_get_uint32, 288 {1, UINT16_MAX, 32}, {32} }, 289 290 { "_shutack_wait_bound", MOD_PROTO_SCTP, 291 mod_set_uint32, mod_get_uint32, 292 {0, 300*SECONDS, 60*SECONDS}, {60*SECONDS} }, 293 294 { "_maxburst", MOD_PROTO_SCTP, 295 mod_set_uint32, mod_get_uint32, 296 {2, 8, 4}, {4} }, 297 298 /* tunable - 30 */ 299 { "_addip_enabled", MOD_PROTO_SCTP, 300 mod_set_boolean, mod_get_boolean, 301 {B_FALSE}, {B_FALSE} }, 302 303 { "_recv_hiwat_minmss", MOD_PROTO_SCTP, 304 mod_set_uint32, mod_get_uint32, 305 {1, 65536, 4}, {4} }, 306 307 { "_slow_start_initial", MOD_PROTO_SCTP, 308 mod_set_uint32, mod_get_uint32, 309 {1, 16, 4}, {4} }, 310 311 { "_slow_start_after_idle", MOD_PROTO_SCTP, 312 mod_set_uint32, mod_get_uint32, 313 {1, 16384, 4}, {4} }, 314 315 { "_prsctp_enabled", MOD_PROTO_SCTP, 316 mod_set_boolean, mod_get_boolean, 317 {B_TRUE}, {B_TRUE} }, 318 319 { "_fast_rxt_thresh", MOD_PROTO_SCTP, 320 mod_set_uint32, mod_get_uint32, 321 {1, 10000, 3}, {3} }, 322 323 { "_deferred_acks_max", MOD_PROTO_SCTP, 324 mod_set_uint32, mod_get_uint32, 325 { 1, 16, 2}, {2} }, 326 327 /* 328 * sctp_wroff_xtra is the extra space in front of SCTP/IP header 329 * for link layer header. It has to be a multiple of 8. 330 */ 331 { "_wroff_xtra", MOD_PROTO_SCTP, 332 mod_set_aligned, mod_get_uint32, 333 {0, 256, 32}, {32} }, 334 335 { "extra_priv_ports", MOD_PROTO_SCTP, 336 mod_set_extra_privports, mod_get_extra_privports, 337 {1, ULP_MAX_PORT, 0}, {0} }, 338 339 { "_listener_limit_conf", MOD_PROTO_SCTP, 340 NULL, sctp_listener_conf_get, {0}, {0} }, 341 342 { "_listener_limit_conf_add", MOD_PROTO_SCTP, 343 sctp_listener_conf_add, NULL, {0}, {0} }, 344 345 { "_listener_limit_conf_del", MOD_PROTO_SCTP, 346 sctp_listener_conf_del, NULL, {0}, {0} }, 347 348 { "?", MOD_PROTO_SCTP, NULL, mod_get_allprop, {0}, {0} }, 349 350 { NULL, 0, NULL, NULL, {0}, {0} } 351 }; 352 353 int sctp_propinfo_count = A_CNT(sctp_propinfo_tbl); 354