xref: /illumos-gate/usr/src/uts/common/inet/tcp/tcp_tunables.c (revision 7a6d80f1660abd4755c68cbd094d4a914681d26e)
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  * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright 2016 Joyent, Inc.
24  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
25  * Copyright (c) 2012, 2017 by Delphix. All rights reserved.
26  * Copyright 2022 Garrett D'Amore
27  */
28 /* Copyright (c) 1990 Mentat Inc. */
29 
30 #include <inet/ip.h>
31 #include <inet/tcp_impl.h>
32 #include <inet/cc.h>
33 #include <sys/sunddi.h>
34 
35 /* Max size IP datagram is 64k - 1 */
36 #define	TCP_MSS_MAX_IPV4 (IP_MAXPACKET - (sizeof (ipha_t) + sizeof (tcpha_t)))
37 #define	TCP_MSS_MAX_IPV6 (IP_MAXPACKET - (sizeof (ip6_t) + sizeof (tcpha_t)))
38 
39 /* Max of the above */
40 #define	TCP_MSS_MAX		TCP_MSS_MAX_IPV4
41 
42 typedef struct {
43 	char *ccn_buf;
44 	uint_t ccn_bufsize;
45 	uint_t ccn_bytes;
46 } tcp_copy_ccname_t;
47 
48 /*
49  * Set the RFC 1948 pass phrase
50  */
51 /* ARGSUSED */
52 static int
53 tcp_set_1948phrase(netstack_t *stack,  cred_t *cr, mod_prop_info_t *pinfo,
54     const char *ifname, const void* pr_val, uint_t flags)
55 {
56 	if (flags & MOD_PROP_DEFAULT)
57 		return (ENOTSUP);
58 
59 	/*
60 	 * Basically, value contains a new pass phrase.  Pass it along!
61 	 */
62 	tcp_iss_key_init((uint8_t *)pr_val, strlen(pr_val),
63 	    stack->netstack_tcp);
64 	return (0);
65 }
66 
67 /*
68  * returns the current list of listener limit configuration.
69  */
70 /* ARGSUSED */
71 static int
72 tcp_listener_conf_get(netstack_t *stack, mod_prop_info_t *pinfo,
73     const char *ifname, void *val, uint_t psize, uint_t flags)
74 {
75 	tcp_stack_t	*tcps = stack->netstack_tcp;
76 	tcp_listener_t	*tl;
77 	char		*pval = val;
78 	size_t		nbytes = 0, tbytes = 0;
79 	uint_t		size;
80 	int		err = 0;
81 
82 	bzero(pval, psize);
83 	size = psize;
84 
85 	if (flags & (MOD_PROP_DEFAULT|MOD_PROP_PERM|MOD_PROP_POSSIBLE))
86 		return (0);
87 
88 	mutex_enter(&tcps->tcps_listener_conf_lock);
89 	for (tl = list_head(&tcps->tcps_listener_conf); tl != NULL;
90 	    tl = list_next(&tcps->tcps_listener_conf, tl)) {
91 		if (psize == size)
92 			nbytes = snprintf(pval, size, "%d:%d",  tl->tl_port,
93 			    tl->tl_ratio);
94 		else
95 			nbytes = snprintf(pval, size, ",%d:%d",  tl->tl_port,
96 			    tl->tl_ratio);
97 		size -= nbytes;
98 		pval += nbytes;
99 		tbytes += nbytes;
100 		if (tbytes >= psize) {
101 			/* Buffer overflow, stop copying information */
102 			err = ENOBUFS;
103 			break;
104 		}
105 	}
106 
107 	mutex_exit(&tcps->tcps_listener_conf_lock);
108 	return (err);
109 }
110 
111 /*
112  * add a new listener limit configuration.
113  */
114 /* ARGSUSED */
115 static int
116 tcp_listener_conf_add(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
117     const char *ifname, const void* pval, uint_t flags)
118 {
119 	tcp_listener_t	*new_tl;
120 	tcp_listener_t	*tl;
121 	long		lport;
122 	long		ratio;
123 	char		*colon;
124 	tcp_stack_t	*tcps = stack->netstack_tcp;
125 
126 	if (flags & MOD_PROP_DEFAULT)
127 		return (ENOTSUP);
128 
129 	if (ddi_strtol(pval, &colon, 10, &lport) != 0 || lport <= 0 ||
130 	    lport > USHRT_MAX || *colon != ':') {
131 		return (EINVAL);
132 	}
133 	if (ddi_strtol(colon + 1, NULL, 10, &ratio) != 0 || ratio <= 0)
134 		return (EINVAL);
135 
136 	mutex_enter(&tcps->tcps_listener_conf_lock);
137 	for (tl = list_head(&tcps->tcps_listener_conf); tl != NULL;
138 	    tl = list_next(&tcps->tcps_listener_conf, tl)) {
139 		/* There is an existing entry, so update its ratio value. */
140 		if (tl->tl_port == lport) {
141 			tl->tl_ratio = ratio;
142 			mutex_exit(&tcps->tcps_listener_conf_lock);
143 			return (0);
144 		}
145 	}
146 
147 	if ((new_tl = kmem_alloc(sizeof (tcp_listener_t), KM_NOSLEEP)) ==
148 	    NULL) {
149 		mutex_exit(&tcps->tcps_listener_conf_lock);
150 		return (ENOMEM);
151 	}
152 
153 	new_tl->tl_port = lport;
154 	new_tl->tl_ratio = ratio;
155 	list_insert_tail(&tcps->tcps_listener_conf, new_tl);
156 	mutex_exit(&tcps->tcps_listener_conf_lock);
157 	return (0);
158 }
159 
160 /*
161  * remove a listener limit configuration.
162  */
163 /* ARGSUSED */
164 static int
165 tcp_listener_conf_del(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
166     const char *ifname, const void* pval, uint_t flags)
167 {
168 	tcp_listener_t	*tl;
169 	long		lport;
170 	tcp_stack_t	*tcps = stack->netstack_tcp;
171 
172 	if (flags & MOD_PROP_DEFAULT)
173 		return (ENOTSUP);
174 
175 	if (ddi_strtol(pval, NULL, 10, &lport) != 0 || lport <= 0 ||
176 	    lport > USHRT_MAX) {
177 		return (EINVAL);
178 	}
179 	mutex_enter(&tcps->tcps_listener_conf_lock);
180 	for (tl = list_head(&tcps->tcps_listener_conf); tl != NULL;
181 	    tl = list_next(&tcps->tcps_listener_conf, tl)) {
182 		if (tl->tl_port == lport) {
183 			list_remove(&tcps->tcps_listener_conf, tl);
184 			mutex_exit(&tcps->tcps_listener_conf_lock);
185 			kmem_free(tl, sizeof (tcp_listener_t));
186 			return (0);
187 		}
188 	}
189 	mutex_exit(&tcps->tcps_listener_conf_lock);
190 	return (ESRCH);
191 }
192 
193 static int
194 tcp_set_buf_prop(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
195     const char *ifname, const void *pval, uint_t flags)
196 {
197 	return (mod_set_buf_prop(stack->netstack_tcp->tcps_propinfo_tbl, stack,
198 	    cr, pinfo, ifname, pval, flags));
199 }
200 
201 static int
202 tcp_get_buf_prop(netstack_t *stack, mod_prop_info_t *pinfo, const char *ifname,
203     void *val, uint_t psize, uint_t flags)
204 {
205 	return (mod_get_buf_prop(stack->netstack_tcp->tcps_propinfo_tbl, stack,
206 	    pinfo, ifname, val, psize, flags));
207 }
208 
209 /*
210  * Special checkers for smallest/largest anonymous port so they don't
211  * ever happen to be (largest < smallest).
212  */
213 /* ARGSUSED */
214 static int
215 tcp_smallest_anon_set(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
216     const char *ifname, const void *pval, uint_t flags)
217 {
218 	unsigned long new_value;
219 	tcp_stack_t *tcps = stack->netstack_tcp;
220 	int err;
221 
222 	if ((err = mod_uint32_value(pval, pinfo, flags, &new_value)) != 0)
223 		return (err);
224 	/* mod_uint32_value() + pinfo guarantees we're in TCP port range. */
225 	if ((uint32_t)new_value > tcps->tcps_largest_anon_port)
226 		return (ERANGE);
227 	pinfo->prop_cur_uval = (uint32_t)new_value;
228 	return (0);
229 }
230 
231 /* ARGSUSED */
232 static int
233 tcp_largest_anon_set(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
234     const char *ifname, const void *pval, uint_t flags)
235 {
236 	unsigned long new_value;
237 	tcp_stack_t *tcps = stack->netstack_tcp;
238 	int err;
239 
240 	if ((err = mod_uint32_value(pval, pinfo, flags, &new_value)) != 0)
241 		return (err);
242 	/* mod_uint32_value() + pinfo guarantees we're in TCP port range. */
243 	if ((uint32_t)new_value < tcps->tcps_smallest_anon_port)
244 		return (ERANGE);
245 	pinfo->prop_cur_uval = (uint32_t)new_value;
246 	return (0);
247 }
248 
249 /* ARGSUSED */
250 static int
251 tcp_set_cc_algorithm(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
252     const char *ifname, const void *pval, uint_t flags)
253 {
254 	tcp_stack_t *tcps = stack->netstack_tcp;
255 	char *name = (flags & MOD_PROP_DEFAULT) ?
256 	    CC_DEFAULT_ALGO_NAME : (char *)pval;
257 	struct cc_algo *algo = cc_load_algo(name);
258 
259 	if (algo == NULL) {
260 		return (EINVAL);
261 	}
262 
263 	tcps->tcps_default_cc_algo = algo;
264 
265 	return (0);
266 }
267 
268 static int
269 tcp_copy_ccname(void *data, struct cc_algo *algo)
270 {
271 	tcp_copy_ccname_t *cd = data;
272 	char *sep = cd->ccn_bytes > 0 ? "," : "";
273 	size_t avail = 0;
274 
275 	if (cd->ccn_bytes < cd->ccn_bufsize) {
276 		avail = cd->ccn_bufsize - cd->ccn_bytes;
277 	}
278 
279 	cd->ccn_bytes += snprintf(cd->ccn_buf + cd->ccn_bytes, avail,
280 	    "%s%s", sep, algo->name);
281 
282 	return (cd->ccn_bytes >= cd->ccn_bufsize ? ENOBUFS : 0);
283 }
284 
285 /* ARGSUSED */
286 static int
287 tcp_get_cc_algorithm(netstack_t *stack, mod_prop_info_t *pinfo,
288     const char *ifname, void *pval, uint_t psize, uint_t flags)
289 {
290 	size_t nbytes;
291 
292 	if (flags & MOD_PROP_POSSIBLE) {
293 		tcp_copy_ccname_t cd = { pval, psize, 0 };
294 		return (cc_walk_algos(tcp_copy_ccname, &cd));
295 	} else if (flags & MOD_PROP_PERM) {
296 		nbytes = snprintf(pval, psize, "%u", MOD_PROP_PERM_RW);
297 	} else if (flags & MOD_PROP_DEFAULT) {
298 		nbytes = snprintf(pval, psize, "%s", CC_DEFAULT_ALGO_NAME);
299 	} else {
300 		nbytes = snprintf(pval, psize, "%s",
301 		    stack->netstack_tcp->tcps_default_cc_algo->name);
302 	}
303 	if (nbytes >= psize)
304 		return (ENOBUFS);
305 	return (0);
306 }
307 
308 /*
309  * All of these are alterable, within the min/max values given, at run time.
310  *
311  * Note: All those tunables which do not start with "_" are Committed and
312  * therefore are public. See PSARC 2010/080.
313  */
314 mod_prop_info_t tcp_propinfo_tbl[] = {
315 	/* tunable - 0 */
316 	{ "_time_wait_interval", MOD_PROTO_TCP,
317 	    mod_set_uint32, mod_get_uint32,
318 	    {1*SECONDS, TCP_TIME_WAIT_MAX, 1*MINUTES}, {1*MINUTES} },
319 
320 	{ "_conn_req_max_q", MOD_PROTO_TCP,
321 	    mod_set_uint32, mod_get_uint32,
322 	    {1, UINT32_MAX, 128}, {128} },
323 
324 	{ "_conn_req_max_q0", MOD_PROTO_TCP,
325 	    mod_set_uint32, mod_get_uint32,
326 	    {0, UINT32_MAX, 1024}, {1024} },
327 
328 	{ "_conn_req_min", MOD_PROTO_TCP,
329 	    mod_set_uint32, mod_get_uint32,
330 	    {1, 1024, 1}, {1} },
331 
332 	{ "_conn_grace_period", MOD_PROTO_TCP,
333 	    mod_set_uint32, mod_get_uint32,
334 	    {0*MS, 20*SECONDS, 0*MS}, {0*MS} },
335 
336 	{ "_cwnd_max", MOD_PROTO_TCP,
337 	    mod_set_uint32, mod_get_uint32,
338 	    {128, ULP_MAX_BUF, 1024*1024}, {1024*1024} },
339 
340 	{ "_debug", MOD_PROTO_TCP,
341 	    mod_set_uint32, mod_get_uint32,
342 	    {0, 10, 0}, {0} },
343 
344 	{ "smallest_nonpriv_port", MOD_PROTO_TCP,
345 	    mod_set_uint32, mod_get_uint32,
346 	    {1024, (32*1024), 1024}, {1024} },
347 
348 	{ "_ip_abort_cinterval", MOD_PROTO_TCP,
349 	    mod_set_uint32, mod_get_uint32,
350 	    {1*SECONDS, UINT32_MAX, 3*MINUTES}, {3*MINUTES} },
351 
352 	{ "_ip_abort_linterval", MOD_PROTO_TCP,
353 	    mod_set_uint32, mod_get_uint32,
354 	    {1*SECONDS, UINT32_MAX, 3*MINUTES}, {3*MINUTES} },
355 
356 	/* tunable - 10 */
357 	{ "_ip_abort_interval", MOD_PROTO_TCP,
358 	    mod_set_uint32, mod_get_uint32,
359 	    {500*MS, UINT32_MAX, 5*MINUTES}, {5*MINUTES} },
360 
361 	{ "_ip_notify_cinterval", MOD_PROTO_TCP,
362 	    mod_set_uint32, mod_get_uint32,
363 	    {1*SECONDS, UINT32_MAX, 10*SECONDS},
364 	    {10*SECONDS} },
365 
366 	{ "_ip_notify_interval", MOD_PROTO_TCP,
367 	    mod_set_uint32, mod_get_uint32,
368 	    {500*MS, UINT32_MAX, 10*SECONDS}, {10*SECONDS} },
369 
370 	{ "_ipv4_ttl", MOD_PROTO_TCP,
371 	    mod_set_uint32, mod_get_uint32,
372 	    {1, 255, 64}, {64} },
373 
374 	{ "_keepalive_interval", MOD_PROTO_TCP,
375 	    mod_set_uint32, mod_get_uint32,
376 	    {1*SECONDS, 10*DAYS, 2*HOURS}, {2*HOURS} },
377 
378 	{ "_maxpsz_multiplier", MOD_PROTO_TCP,
379 	    mod_set_uint32, mod_get_uint32,
380 	    {0, 100, 10}, {10} },
381 
382 	{ "_mss_def_ipv4", MOD_PROTO_TCP,
383 	    mod_set_uint32, mod_get_uint32,
384 	    {1, TCP_MSS_MAX_IPV4, 536}, {536} },
385 
386 	{ "_mss_max_ipv4", MOD_PROTO_TCP,
387 	    mod_set_uint32, mod_get_uint32,
388 	    {1, TCP_MSS_MAX_IPV4, TCP_MSS_MAX_IPV4},
389 	    {TCP_MSS_MAX_IPV4} },
390 
391 	{ "_mss_min", MOD_PROTO_TCP,
392 	    mod_set_uint32, mod_get_uint32,
393 	    {1, TCP_MSS_MAX, 108}, {108} },
394 
395 	{ "_naglim_def", MOD_PROTO_TCP,
396 	    mod_set_uint32, mod_get_uint32,
397 	    {1, (64*1024)-1, (4*1024)-1}, {(4*1024)-1} },
398 
399 	/* tunable - 20 */
400 	{ "_rexmit_interval_initial", MOD_PROTO_TCP,
401 	    mod_set_uint32, mod_get_uint32,
402 	    {1*MS, 20*SECONDS, 1*SECONDS}, {1*SECONDS} },
403 
404 	{ "_rexmit_interval_max", MOD_PROTO_TCP,
405 	    mod_set_uint32, mod_get_uint32,
406 	    {1*MS, 2*HOURS, 60*SECONDS}, {60*SECONDS} },
407 
408 	{ "_rexmit_interval_min", MOD_PROTO_TCP,
409 	    mod_set_uint32, mod_get_uint32,
410 	    {1*MS, 2*HOURS, 400*MS}, {400*MS} },
411 
412 	{ "_deferred_ack_interval", MOD_PROTO_TCP,
413 	    mod_set_uint32, mod_get_uint32,
414 	    {1*MS, 1*MINUTES, 100*MS}, {100*MS} },
415 
416 	{ "_snd_lowat_fraction", MOD_PROTO_TCP,
417 	    mod_set_uint32, mod_get_uint32,
418 	    {0, 16, 10}, {10} },
419 
420 	{ "_dupack_fast_retransmit", MOD_PROTO_TCP,
421 	    mod_set_uint32, mod_get_uint32,
422 	    {1, 10000, 3}, {3} },
423 
424 	{ "_ignore_path_mtu", MOD_PROTO_TCP,
425 	    mod_set_boolean, mod_get_boolean,
426 	    {B_FALSE}, {B_FALSE} },
427 
428 	{ "smallest_anon_port", MOD_PROTO_TCP,
429 	    tcp_smallest_anon_set, mod_get_uint32,
430 	    {1024, ULP_MAX_PORT, 32*1024}, {32*1024} },
431 
432 	{ "largest_anon_port", MOD_PROTO_TCP,
433 	    tcp_largest_anon_set, mod_get_uint32,
434 	    {1024, ULP_MAX_PORT, ULP_MAX_PORT},
435 	    {ULP_MAX_PORT} },
436 
437 	{ "send_buf", MOD_PROTO_TCP,
438 	    tcp_set_buf_prop, tcp_get_buf_prop,
439 	    {TCP_XMIT_LOWATER, ULP_MAX_BUF, TCP_XMIT_HIWATER},
440 	    {TCP_XMIT_HIWATER} },
441 
442 	/* tunable - 30 */
443 	{ "_xmit_lowat", MOD_PROTO_TCP,
444 	    mod_set_uint32, mod_get_uint32,
445 	    {TCP_XMIT_LOWATER, ULP_MAX_BUF, TCP_XMIT_LOWATER},
446 	    {TCP_XMIT_LOWATER} },
447 
448 	{ "recv_buf", MOD_PROTO_TCP,
449 	    tcp_set_buf_prop, tcp_get_buf_prop,
450 	    {TCP_RECV_LOWATER, ULP_MAX_BUF, TCP_RECV_HIWATER},
451 	    {TCP_RECV_HIWATER} },
452 
453 	{ "_recv_hiwat_minmss", MOD_PROTO_TCP,
454 	    mod_set_uint32, mod_get_uint32,
455 	    {1, 65536, 4}, {4} },
456 
457 	{ "_fin_wait_2_flush_interval", MOD_PROTO_TCP,
458 	    mod_set_uint32, mod_get_uint32,
459 	    {1*SECONDS, 2*HOURS, 60*SECONDS},
460 	    {60*SECONDS} },
461 
462 	{ "max_buf", MOD_PROTO_TCP,
463 	    mod_set_uint32, mod_get_uint32,
464 	    {8192, ULP_MAX_BUF, 1024*1024}, {1024*1024} },
465 
466 	{ "_strong_iss", MOD_PROTO_TCP,
467 	    mod_set_uint32, mod_get_uint32,
468 	    {0, 2, 2}, {2} },
469 
470 	{ "_rtt_updates", MOD_PROTO_TCP,
471 	    mod_set_uint32, mod_get_uint32,
472 	    {0, 65536, 20}, {20} },
473 
474 	{ "_wscale_always", MOD_PROTO_TCP,
475 	    mod_set_boolean, mod_get_boolean,
476 	    {B_TRUE}, {B_TRUE} },
477 
478 	{ "_tstamp_always", MOD_PROTO_TCP,
479 	    mod_set_boolean, mod_get_boolean,
480 	    {B_FALSE}, {B_FALSE} },
481 
482 	{ "_tstamp_if_wscale", MOD_PROTO_TCP,
483 	    mod_set_boolean, mod_get_boolean,
484 	    {B_TRUE}, {B_TRUE} },
485 
486 	/* tunable - 40 */
487 	{ "_rexmit_interval_extra", MOD_PROTO_TCP,
488 	    mod_set_uint32, mod_get_uint32,
489 	    {0*MS, 2*HOURS, 0*MS}, {0*MS} },
490 
491 	{ "_deferred_acks_max", MOD_PROTO_TCP,
492 	    mod_set_uint32, mod_get_uint32,
493 	    {0, 16, 2}, {2} },
494 
495 	{ "_slow_start_after_idle", MOD_PROTO_TCP,
496 	    mod_set_uint32, mod_get_uint32,
497 	    {0, 16384, 0}, {0} },
498 
499 	{ "_slow_start_initial", MOD_PROTO_TCP,
500 	    mod_set_uint32, mod_get_uint32,
501 	    {0, 16, 0}, {0} },
502 
503 	{ "sack", MOD_PROTO_TCP,
504 	    mod_set_uint32, mod_get_uint32,
505 	    {0, 2, 2}, {2} },
506 
507 	{ "_ipv6_hoplimit", MOD_PROTO_TCP,
508 	    mod_set_uint32, mod_get_uint32,
509 	    {0, IPV6_MAX_HOPS, IPV6_DEFAULT_HOPS},
510 	    {IPV6_DEFAULT_HOPS} },
511 
512 	{ "_mss_def_ipv6", MOD_PROTO_TCP,
513 	    mod_set_uint32, mod_get_uint32,
514 	    {1, TCP_MSS_MAX_IPV6, 1220}, {1220} },
515 
516 	{ "_mss_max_ipv6", MOD_PROTO_TCP,
517 	    mod_set_uint32, mod_get_uint32,
518 	    {1, TCP_MSS_MAX_IPV6, TCP_MSS_MAX_IPV6},
519 	    {TCP_MSS_MAX_IPV6} },
520 
521 	{ "_rev_src_routes", MOD_PROTO_TCP,
522 	    mod_set_boolean, mod_get_boolean,
523 	    {B_FALSE}, {B_FALSE} },
524 
525 	{ "_local_dack_interval", MOD_PROTO_TCP,
526 	    mod_set_uint32, mod_get_uint32,
527 	    {10*MS, 500*MS, 50*MS}, {50*MS} },
528 
529 	/* tunable - 50 */
530 	{ "_local_dacks_max", MOD_PROTO_TCP,
531 	    mod_set_uint32, mod_get_uint32,
532 	    {0, 16, 8}, {8} },
533 
534 	{ "ecn", MOD_PROTO_TCP,
535 	    mod_set_uint32, mod_get_uint32,
536 	    {0, 2, 1}, {1} },
537 
538 	{ "_rst_sent_rate_enabled", MOD_PROTO_TCP,
539 	    mod_set_boolean, mod_get_boolean,
540 	    {B_TRUE}, {B_TRUE} },
541 
542 	{ "_rst_sent_rate", MOD_PROTO_TCP,
543 	    mod_set_uint32, mod_get_uint32,
544 	    {0, UINT32_MAX, 40}, {40} },
545 
546 	{ "_push_timer_interval", MOD_PROTO_TCP,
547 	    mod_set_uint32, mod_get_uint32,
548 	    {0, 100*MS, 50*MS}, {50*MS} },
549 
550 	{ "_use_smss_as_mss_opt", MOD_PROTO_TCP,
551 	    mod_set_boolean, mod_get_boolean,
552 	    {B_FALSE}, {B_FALSE} },
553 
554 	{ "_keepalive_abort_interval", MOD_PROTO_TCP,
555 	    mod_set_uint32, mod_get_uint32,
556 	    {0, UINT32_MAX, 8*MINUTES}, {8*MINUTES} },
557 
558 	/*
559 	 * tcp_wroff_xtra is the extra space in front of TCP/IP header for link
560 	 * layer header.  It has to be a multiple of 8.
561 	 */
562 	{ "_wroff_xtra", MOD_PROTO_TCP,
563 	    mod_set_aligned, mod_get_uint32,
564 	    {0, 256, 32}, {32} },
565 
566 	{ "_dev_flow_ctl", MOD_PROTO_TCP,
567 	    mod_set_boolean, mod_get_boolean,
568 	    {B_FALSE}, {B_FALSE} },
569 
570 	{ "_reass_timeout", MOD_PROTO_TCP,
571 	    mod_set_uint32, mod_get_uint32,
572 	    {0, UINT32_MAX, 100*SECONDS}, {100*SECONDS} },
573 
574 	/* tunable - 60 */
575 	{ "extra_priv_ports", MOD_PROTO_TCP,
576 	    mod_set_extra_privports, mod_get_extra_privports,
577 	    {1, ULP_MAX_PORT, 0}, {0} },
578 
579 	{ "_1948_phrase", MOD_PROTO_TCP,
580 	    tcp_set_1948phrase, NULL, {0}, {0} },
581 
582 	{ "_listener_limit_conf", MOD_PROTO_TCP,
583 	    NULL, tcp_listener_conf_get, {0}, {0} },
584 
585 	{ "_listener_limit_conf_add", MOD_PROTO_TCP,
586 	    tcp_listener_conf_add, NULL, {0}, {0} },
587 
588 	{ "_listener_limit_conf_del", MOD_PROTO_TCP,
589 	    tcp_listener_conf_del, NULL, {0}, {0} },
590 
591 	{ "_iss_incr", MOD_PROTO_TCP,
592 	    mod_set_uint32, mod_get_uint32,
593 	    {1, ISS_INCR, ISS_INCR},
594 	    {ISS_INCR} },
595 
596 	{ "congestion_control", MOD_PROTO_TCP,
597 	    tcp_set_cc_algorithm, tcp_get_cc_algorithm, {0}, {0} },
598 
599 	/* RFC 3465 - TCP Congestion Control with Appropriate Byte Counting */
600 	{ "_abc", MOD_PROTO_TCP,
601 	    mod_set_boolean, mod_get_boolean, {B_TRUE}, {B_TRUE} },
602 
603 	/* "L" value from RFC 3465 */
604 	{ "_abc_l_var", MOD_PROTO_TCP,
605 	    mod_set_uint32, mod_get_uint32, {1, UINT32_MAX, 2}, {2} },
606 
607 	{ "?", MOD_PROTO_TCP, NULL, mod_get_allprop, {0}, {0} },
608 
609 	{ NULL, 0, NULL, NULL, {0}, {0} }
610 };
611 
612 int tcp_propinfo_count = A_CNT(tcp_propinfo_tbl);
613