Print this page
3942 inject sanity into ipadm tcp buffer size properties
3943 _snd_lowat_fraction tcp tunable has no effect
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: Peng Dai <peng.dai@delphix.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/inet/tunables.c
+++ new/usr/src/uts/common/inet/tunables.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 * Copyright (c) 1990 Mentat Inc.
24 + * Copyright (c) 2013 by Delphix. All rights reserved.
24 25 */
25 26
26 27 #include <inet/tunables.h>
27 28 #include <sys/md5.h>
28 29 #include <inet/common.h>
29 30 #include <inet/ip.h>
30 31 #include <inet/ip6.h>
31 32 #include <netinet/icmp6.h>
32 33 #include <inet/ip_stack.h>
33 34 #include <inet/rawip_impl.h>
34 35 #include <inet/tcp_stack.h>
35 36 #include <inet/tcp_impl.h>
36 37 #include <inet/udp_impl.h>
37 38 #include <inet/sctp/sctp_stack.h>
38 39 #include <inet/sctp/sctp_impl.h>
39 40 #include <inet/tunables.h>
40 41
42 +mod_prop_info_t *
43 +mod_prop_lookup(mod_prop_info_t ptbl[], const char *prop_name, uint_t proto)
44 +{
45 + mod_prop_info_t *pinfo;
46 +
47 + /*
48 + * Walk the ptbl array looking for a property that has the requested
49 + * name and protocol number. Note that we assume that all protocol
50 + * tables are terminated by an entry with a NULL property name.
51 + */
52 + for (pinfo = ptbl; pinfo->mpi_name != NULL; pinfo++) {
53 + if (strcmp(pinfo->mpi_name, prop_name) == 0 &&
54 + pinfo->mpi_proto == proto)
55 + return (pinfo);
56 + }
57 + return (NULL);
58 +}
59 +
41 60 static int
42 61 prop_perm2const(mod_prop_info_t *pinfo)
43 62 {
44 63 if (pinfo->mpi_setf == NULL)
45 64 return (MOD_PROP_PERM_READ);
46 65 if (pinfo->mpi_getf == NULL)
47 66 return (MOD_PROP_PERM_WRITE);
48 67 return (MOD_PROP_PERM_RW);
49 68 }
50 69
51 70 /*
52 71 * Modifies the value of the property to default value or to the `pval'
53 72 * specified by the user.
54 73 */
55 74 /* ARGSUSED */
56 75 int
57 -mod_set_boolean(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
76 +mod_set_boolean(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
58 77 const char *ifname, const void* pval, uint_t flags)
59 78 {
60 - char *end;
61 - unsigned long new_value;
79 + char *end;
80 + unsigned long new_value;
62 81
63 82 if (flags & MOD_PROP_DEFAULT) {
64 83 pinfo->prop_cur_bval = pinfo->prop_def_bval;
65 84 return (0);
66 85 }
67 86
68 87 if (ddi_strtoul(pval, &end, 10, &new_value) != 0 || *end != '\0')
69 88 return (EINVAL);
70 89 if (new_value != B_TRUE && new_value != B_FALSE)
71 90 return (EINVAL);
72 91 pinfo->prop_cur_bval = new_value;
73 92 return (0);
74 93 }
75 94
76 95 /*
77 96 * Retrieves property permission, default value, current value or possible
78 97 * values for those properties whose value type is boolean_t.
79 98 */
80 99 /* ARGSUSED */
81 100 int
82 -mod_get_boolean(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
101 +mod_get_boolean(netstack_t *stack, mod_prop_info_t *pinfo, const char *ifname,
83 102 void *pval, uint_t psize, uint_t flags)
84 103 {
85 104 boolean_t get_def = (flags & MOD_PROP_DEFAULT);
86 105 boolean_t get_perm = (flags & MOD_PROP_PERM);
87 106 boolean_t get_range = (flags & MOD_PROP_POSSIBLE);
88 107 size_t nbytes;
89 108
90 109 bzero(pval, psize);
91 110 if (get_perm)
92 111 nbytes = snprintf(pval, psize, "%u", prop_perm2const(pinfo));
93 112 else if (get_range)
94 113 nbytes = snprintf(pval, psize, "%u,%u", B_FALSE, B_TRUE);
95 114 else if (get_def)
96 115 nbytes = snprintf(pval, psize, "%u", pinfo->prop_def_bval);
97 116 else
98 117 nbytes = snprintf(pval, psize, "%u", pinfo->prop_cur_bval);
99 118 if (nbytes >= psize)
100 119 return (ENOBUFS);
101 120 return (0);
102 121 }
103 122
104 123 int
105 124 mod_uint32_value(const void *pval, mod_prop_info_t *pinfo, uint_t flags,
106 125 ulong_t *new_value)
107 126 {
108 127 char *end;
109 128
110 129 if (flags & MOD_PROP_DEFAULT) {
111 130 *new_value = pinfo->prop_def_uval;
112 131 return (0);
113 132 }
114 133
115 134 if (ddi_strtoul(pval, &end, 10, (ulong_t *)new_value) != 0 ||
116 135 *end != '\0')
117 136 return (EINVAL);
118 137 if (*new_value < pinfo->prop_min_uval ||
119 138 *new_value > pinfo->prop_max_uval) {
120 139 return (ERANGE);
↓ open down ↓ |
28 lines elided |
↑ open up ↑ |
121 140 }
122 141 return (0);
123 142 }
124 143
125 144 /*
126 145 * Modifies the value of the property to default value or to the `pval'
127 146 * specified by the user.
128 147 */
129 148 /* ARGSUSED */
130 149 int
131 -mod_set_uint32(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
150 +mod_set_uint32(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
132 151 const char *ifname, const void *pval, uint_t flags)
133 152 {
134 153 unsigned long new_value;
135 154 int err;
136 155
137 156 if ((err = mod_uint32_value(pval, pinfo, flags, &new_value)) != 0)
138 157 return (err);
139 158 pinfo->prop_cur_uval = (uint32_t)new_value;
140 159 return (0);
141 160 }
142 161
143 162 /*
144 163 * Rounds up the value to make it multiple of 8.
145 164 */
146 165 /* ARGSUSED */
147 166 int
148 -mod_set_aligned(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
167 +mod_set_aligned(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
149 168 const char *ifname, const void* pval, uint_t flags)
150 169 {
151 170 int err;
152 171
153 - if ((err = mod_set_uint32(cbarg, cr, pinfo, ifname, pval, flags)) != 0)
172 + if ((err = mod_set_uint32(stack, cr, pinfo, ifname, pval, flags)) != 0)
154 173 return (err);
155 174
156 175 /* if required, align the value to multiple of 8 */
157 176 if (pinfo->prop_cur_uval & 0x7) {
158 177 pinfo->prop_cur_uval &= ~0x7;
159 178 pinfo->prop_cur_uval += 0x8;
160 179 }
161 180
162 181 return (0);
163 182 }
164 183
165 184 /*
166 185 * Retrieves property permission, default value, current value or possible
167 186 * values for those properties whose value type is uint32_t.
168 187 */
169 188 /* ARGSUSED */
170 189 int
171 -mod_get_uint32(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
190 +mod_get_uint32(netstack_t *stack, mod_prop_info_t *pinfo, const char *ifname,
172 191 void *pval, uint_t psize, uint_t flags)
173 192 {
174 193 boolean_t get_def = (flags & MOD_PROP_DEFAULT);
175 194 boolean_t get_perm = (flags & MOD_PROP_PERM);
176 195 boolean_t get_range = (flags & MOD_PROP_POSSIBLE);
177 196 size_t nbytes;
178 197
179 198 bzero(pval, psize);
180 199 if (get_perm)
181 200 nbytes = snprintf(pval, psize, "%u", prop_perm2const(pinfo));
182 201 else if (get_range)
183 202 nbytes = snprintf(pval, psize, "%u-%u",
184 203 pinfo->prop_min_uval, pinfo->prop_max_uval);
↓ open down ↓ |
3 lines elided |
↑ open up ↑ |
185 204 else if (get_def)
186 205 nbytes = snprintf(pval, psize, "%u", pinfo->prop_def_uval);
187 206 else
188 207 nbytes = snprintf(pval, psize, "%u", pinfo->prop_cur_uval);
189 208 if (nbytes >= psize)
190 209 return (ENOBUFS);
191 210 return (0);
192 211 }
193 212
194 213 /*
214 + * The range of the buffer size properties has a static lower bound configured
215 + * in the property info structure of the property itself, and a dynamic upper
216 + * bound. The upper bound is the current value of the "max_buf" property
217 + * in the appropriate protocol property table.
218 + */
219 +static void
220 +mod_get_buf_prop_range(mod_prop_info_t ptbl[], mod_prop_info_t *pinfo,
221 + uint32_t *min, uint32_t *max)
222 +{
223 + mod_prop_info_t *maxbuf_pinfo = mod_prop_lookup(ptbl, "max_buf",
224 + pinfo->mpi_proto);
225 +
226 + *min = pinfo->prop_min_uval;
227 + *max = maxbuf_pinfo->prop_cur_uval;
228 +}
229 +
230 +/*
231 + * Modifies the value of the buffer size property to its default value or to
232 + * the value specified by the user. This is similar to mod_set_uint32() except
233 + * that the value has a dynamically bounded range (see mod_get_buf_prop_range()
234 + * for details).
235 + */
236 +/* ARGSUSED */
237 +int
238 +mod_set_buf_prop(mod_prop_info_t ptbl[], netstack_t *stack, cred_t *cr,
239 + mod_prop_info_t *pinfo, const char *ifname, const void *pval, uint_t flags)
240 +{
241 + unsigned long new_value;
242 + char *end;
243 + uint32_t min, max;
244 +
245 + if (flags & MOD_PROP_DEFAULT) {
246 + pinfo->prop_cur_uval = pinfo->prop_def_uval;
247 + return (0);
248 + }
249 +
250 + if (ddi_strtoul(pval, &end, 10, &new_value) != 0 || *end != '\0')
251 + return (EINVAL);
252 +
253 + mod_get_buf_prop_range(ptbl, pinfo, &min, &max);
254 + if (new_value < min || new_value > max)
255 + return (ERANGE);
256 +
257 + pinfo->prop_cur_uval = new_value;
258 + return (0);
259 +}
260 +
261 +/*
262 + * Retrieves property permissions, default value, current value, or possible
263 + * values for buffer size properties. While these properties have integer
264 + * values, they have a dynamic range (see mod_get_buf_prop_range() for
265 + * details). As such, they need to be handled differently.
266 + */
267 +int
268 +mod_get_buf_prop(mod_prop_info_t ptbl[], netstack_t *stack,
269 + mod_prop_info_t *pinfo, const char *ifname, void *pval, uint_t psize,
270 + uint_t flags)
271 +{
272 + size_t nbytes;
273 + uint32_t min, max;
274 +
275 + if (flags & MOD_PROP_POSSIBLE) {
276 + mod_get_buf_prop_range(ptbl, pinfo, &min, &max);
277 + nbytes = snprintf(pval, psize, "%u-%u", min, max);
278 + return (nbytes < psize ? 0 : ENOBUFS);
279 + }
280 + return (mod_get_uint32(stack, pinfo, ifname, pval, psize, flags));
281 +}
282 +
283 +/*
195 284 * Implements /sbin/ndd -get /dev/ip ?, for all the modules. Needed for
196 285 * backward compatibility with /sbin/ndd.
197 286 */
198 287 /* ARGSUSED */
199 288 int
200 -mod_get_allprop(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
289 +mod_get_allprop(netstack_t *stack, mod_prop_info_t *pinfo, const char *ifname,
201 290 void *val, uint_t psize, uint_t flags)
202 291 {
203 292 char *pval = val;
204 293 mod_prop_info_t *ptbl, *prop;
205 - ip_stack_t *ipst;
206 - tcp_stack_t *tcps;
207 - sctp_stack_t *sctps;
208 - udp_stack_t *us;
209 - icmp_stack_t *is;
210 294 uint_t size;
211 295 size_t nbytes = 0, tbytes = 0;
212 296
213 297 bzero(pval, psize);
214 298 size = psize;
215 299
216 300 switch (pinfo->mpi_proto) {
217 301 case MOD_PROTO_IP:
218 302 case MOD_PROTO_IPV4:
219 303 case MOD_PROTO_IPV6:
220 - ipst = (ip_stack_t *)cbarg;
221 - ptbl = ipst->ips_propinfo_tbl;
304 + ptbl = stack->netstack_ip->ips_propinfo_tbl;
222 305 break;
223 306 case MOD_PROTO_RAWIP:
224 - is = (icmp_stack_t *)cbarg;
225 - ptbl = is->is_propinfo_tbl;
307 + ptbl = stack->netstack_icmp->is_propinfo_tbl;
226 308 break;
227 309 case MOD_PROTO_TCP:
228 - tcps = (tcp_stack_t *)cbarg;
229 - ptbl = tcps->tcps_propinfo_tbl;
310 + ptbl = stack->netstack_tcp->tcps_propinfo_tbl;
230 311 break;
231 312 case MOD_PROTO_UDP:
232 - us = (udp_stack_t *)cbarg;
233 - ptbl = us->us_propinfo_tbl;
313 + ptbl = stack->netstack_udp->us_propinfo_tbl;
234 314 break;
235 315 case MOD_PROTO_SCTP:
236 - sctps = (sctp_stack_t *)cbarg;
237 - ptbl = sctps->sctps_propinfo_tbl;
316 + ptbl = stack->netstack_sctp->sctps_propinfo_tbl;
238 317 break;
239 318 default:
240 319 return (EINVAL);
241 320 }
242 321
243 322 for (prop = ptbl; prop->mpi_name != NULL; prop++) {
244 323 if (prop->mpi_name[0] == '\0' ||
245 324 strcmp(prop->mpi_name, "?") == 0) {
246 325 continue;
247 326 }
248 327 nbytes = snprintf(pval, size, "%s %d %d", prop->mpi_name,
249 328 prop->mpi_proto, prop_perm2const(prop));
250 329 size -= nbytes + 1;
251 330 pval += nbytes + 1;
252 331 tbytes += nbytes + 1;
253 332 if (tbytes >= psize) {
254 333 /* Buffer overflow, stop copying information */
255 334 return (ENOBUFS);
256 335 }
↓ open down ↓ |
9 lines elided |
↑ open up ↑ |
257 336 }
258 337 return (0);
259 338 }
260 339
261 340 /*
262 341 * Hold a lock while changing *_epriv_ports to prevent multiple
263 342 * threads from changing it at the same time.
264 343 */
265 344 /* ARGSUSED */
266 345 int
267 -mod_set_extra_privports(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
346 +mod_set_extra_privports(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
268 347 const char *ifname, const void* val, uint_t flags)
269 348 {
270 349 uint_t proto = pinfo->mpi_proto;
271 350 tcp_stack_t *tcps;
272 351 sctp_stack_t *sctps;
273 352 udp_stack_t *us;
274 353 unsigned long new_value;
275 354 char *end;
276 355 kmutex_t *lock;
277 356 uint_t i, nports;
278 357 in_port_t *ports;
279 358 boolean_t def = (flags & MOD_PROP_DEFAULT);
280 359 const char *pval = val;
281 360
282 361 if (!def) {
283 362 if (ddi_strtoul(pval, &end, 10, &new_value) != 0 ||
284 363 *end != '\0') {
285 364 return (EINVAL);
↓ open down ↓ |
8 lines elided |
↑ open up ↑ |
286 365 }
287 366
288 367 if (new_value < pinfo->prop_min_uval ||
289 368 new_value > pinfo->prop_max_uval) {
290 369 return (ERANGE);
291 370 }
292 371 }
293 372
294 373 switch (proto) {
295 374 case MOD_PROTO_TCP:
296 - tcps = (tcp_stack_t *)cbarg;
375 + tcps = stack->netstack_tcp;
297 376 lock = &tcps->tcps_epriv_port_lock;
298 377 ports = tcps->tcps_g_epriv_ports;
299 378 nports = tcps->tcps_g_num_epriv_ports;
300 379 break;
301 380 case MOD_PROTO_UDP:
302 - us = (udp_stack_t *)cbarg;
381 + us = stack->netstack_udp;
303 382 lock = &us->us_epriv_port_lock;
304 383 ports = us->us_epriv_ports;
305 384 nports = us->us_num_epriv_ports;
306 385 break;
307 386 case MOD_PROTO_SCTP:
308 - sctps = (sctp_stack_t *)cbarg;
387 + sctps = stack->netstack_sctp;
309 388 lock = &sctps->sctps_epriv_port_lock;
310 389 ports = sctps->sctps_g_epriv_ports;
311 390 nports = sctps->sctps_g_num_epriv_ports;
312 391 break;
313 392 default:
314 393 return (ENOTSUP);
315 394 }
316 395
317 396 mutex_enter(lock);
318 397
319 398 /* if MOD_PROP_DEFAULT is set then reset the ports list to default */
320 399 if (def) {
321 400 for (i = 0; i < nports; i++)
322 401 ports[i] = 0;
323 402 ports[0] = ULP_DEF_EPRIV_PORT1;
324 403 ports[1] = ULP_DEF_EPRIV_PORT2;
325 404 mutex_exit(lock);
326 405 return (0);
327 406 }
328 407
329 408 /* Check if the value is already in the list */
330 409 for (i = 0; i < nports; i++) {
331 410 if (new_value == ports[i])
332 411 break;
333 412 }
334 413
335 414 if (flags & MOD_PROP_REMOVE) {
336 415 if (i == nports) {
337 416 mutex_exit(lock);
338 417 return (ESRCH);
339 418 }
340 419 /* Clear the value */
341 420 ports[i] = 0;
342 421 } else if (flags & MOD_PROP_APPEND) {
343 422 if (i != nports) {
344 423 mutex_exit(lock);
345 424 return (EEXIST);
346 425 }
347 426
348 427 /* Find an empty slot */
349 428 for (i = 0; i < nports; i++) {
350 429 if (ports[i] == 0)
351 430 break;
352 431 }
353 432 if (i == nports) {
354 433 mutex_exit(lock);
355 434 return (EOVERFLOW);
356 435 }
357 436 /* Set the new value */
358 437 ports[i] = (in_port_t)new_value;
359 438 } else {
360 439 /*
361 440 * If the user used 'assignment' modifier.
362 441 * For eg:
363 442 * # ipadm set-prop -p extra_priv_ports=3001 tcp
364 443 *
365 444 * We clear all the ports and then just add 3001.
366 445 */
367 446 ASSERT(flags == MOD_PROP_ACTIVE);
368 447 for (i = 0; i < nports; i++)
369 448 ports[i] = 0;
370 449 ports[0] = (in_port_t)new_value;
371 450 }
372 451
373 452 mutex_exit(lock);
374 453 return (0);
↓ open down ↓ |
56 lines elided |
↑ open up ↑ |
375 454 }
376 455
377 456 /*
378 457 * Note: No locks are held when inspecting *_epriv_ports
379 458 * but instead the code relies on:
380 459 * - the fact that the address of the array and its size never changes
381 460 * - the atomic assignment of the elements of the array
382 461 */
383 462 /* ARGSUSED */
384 463 int
385 -mod_get_extra_privports(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
386 - void *val, uint_t psize, uint_t flags)
464 +mod_get_extra_privports(netstack_t *stack, mod_prop_info_t *pinfo,
465 + const char *ifname, void *val, uint_t psize, uint_t flags)
387 466 {
388 467 uint_t proto = pinfo->mpi_proto;
389 468 tcp_stack_t *tcps;
390 469 sctp_stack_t *sctps;
391 470 udp_stack_t *us;
392 471 uint_t i, nports, size;
393 472 in_port_t *ports;
394 473 char *pval = val;
395 474 size_t nbytes = 0, tbytes = 0;
396 475 boolean_t get_def = (flags & MOD_PROP_DEFAULT);
397 476 boolean_t get_perm = (flags & MOD_PROP_PERM);
398 477 boolean_t get_range = (flags & MOD_PROP_POSSIBLE);
399 478
400 479 bzero(pval, psize);
401 480 size = psize;
402 481
403 482 if (get_def) {
↓ open down ↓ |
7 lines elided |
↑ open up ↑ |
404 483 tbytes = snprintf(pval, psize, "%u,%u", ULP_DEF_EPRIV_PORT1,
405 484 ULP_DEF_EPRIV_PORT2);
406 485 goto ret;
407 486 } else if (get_perm) {
408 487 tbytes = snprintf(pval, psize, "%u", MOD_PROP_PERM_RW);
409 488 goto ret;
410 489 }
411 490
412 491 switch (proto) {
413 492 case MOD_PROTO_TCP:
414 - tcps = (tcp_stack_t *)cbarg;
493 + tcps = stack->netstack_tcp;
415 494 ports = tcps->tcps_g_epriv_ports;
416 495 nports = tcps->tcps_g_num_epriv_ports;
417 496 break;
418 497 case MOD_PROTO_UDP:
419 - us = (udp_stack_t *)cbarg;
498 + us = stack->netstack_udp;
420 499 ports = us->us_epriv_ports;
421 500 nports = us->us_num_epriv_ports;
422 501 break;
423 502 case MOD_PROTO_SCTP:
424 - sctps = (sctp_stack_t *)cbarg;
503 + sctps = stack->netstack_sctp;
425 504 ports = sctps->sctps_g_epriv_ports;
426 505 nports = sctps->sctps_g_num_epriv_ports;
427 506 break;
428 507 default:
429 508 return (ENOTSUP);
430 509 }
431 510
432 511 if (get_range) {
433 512 tbytes = snprintf(pval, psize, "%u-%u", pinfo->prop_min_uval,
434 513 pinfo->prop_max_uval);
435 514 goto ret;
436 515 }
437 516
438 517 for (i = 0; i < nports; i++) {
439 518 if (ports[i] != 0) {
440 519 if (psize == size)
441 520 nbytes = snprintf(pval, size, "%u", ports[i]);
442 521 else
443 522 nbytes = snprintf(pval, size, ",%u", ports[i]);
444 523 size -= nbytes;
445 524 pval += nbytes;
446 525 tbytes += nbytes;
447 526 if (tbytes >= psize)
448 527 return (ENOBUFS);
449 528 }
450 529 }
451 530 return (0);
452 531 ret:
453 532 if (tbytes >= psize)
454 533 return (ENOBUFS);
455 534 return (0);
456 535 }
↓ open down ↓ |
22 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX