Print this page
DLPX-25998 TCP congestion control is inadequate
Reviewed at: http://reviews.delphix.com/r/34808/
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/lib/libipadm/common/ipadm_prop.c
+++ new/usr/src/lib/libipadm/common/ipadm_prop.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 *
|
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
13 13 * When distributing Covered Code, include this CDDL HEADER in each
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) 2010, Oracle and/or its affiliates. All rights reserved.
23 - * Copyright (c) 2013 by Delphix. All rights reserved.
23 + * Copyright (c) 2013, 2017 by Delphix. All rights reserved.
24 24 */
25 25
26 26 /*
27 27 * This file contains routines that are used to modify/retrieve protocol or
28 28 * interface property values. It also holds all the supported properties for
29 29 * both IP interface and protocols in `ipadm_prop_desc_t'. Following protocols
30 30 * are supported: IP, IPv4, IPv6, TCP, SCTP, UDP and ICMP.
31 31 *
32 32 * This file also contains walkers, which walks through the property table and
33 33 * calls the callback function, of the form `ipadm_prop_wfunc_t' , for every
34 34 * property in the table.
35 35 */
36 36
37 37 #include <unistd.h>
38 38 #include <errno.h>
39 39 #include <ctype.h>
40 40 #include <fcntl.h>
41 41 #include <strings.h>
42 42 #include <stdlib.h>
43 +#include <sys/types.h>
44 +#include <dirent.h>
43 45 #include <netinet/in.h>
44 46 #include <arpa/inet.h>
45 47 #include <sys/sockio.h>
46 48 #include <assert.h>
47 49 #include <libdllink.h>
48 50 #include <zone.h>
49 51 #include "libipadm_impl.h"
50 52 #include <inet/tunables.h>
51 53
52 54 #define IPADM_NONESTR "none"
53 55 #define DEF_METRIC_VAL 0 /* default metric value */
54 56
55 57 #define A_CNT(arr) (sizeof (arr) / sizeof (arr[0]))
56 58
57 59 static ipadm_status_t i_ipadm_validate_if(ipadm_handle_t, const char *,
58 60 uint_t, uint_t);
59 61
|
↓ open down ↓ |
7 lines elided |
↑ open up ↑ |
60 62 /*
61 63 * Callback functions to retrieve property values from the kernel. These
62 64 * functions, when required, translate the values from the kernel to a format
63 65 * suitable for printing. For example: boolean values will be translated
64 66 * to on/off. They also retrieve DEFAULT, PERM and POSSIBLE values for
65 67 * a given property.
66 68 */
67 69 static ipadm_pd_getf_t i_ipadm_get_prop, i_ipadm_get_ifprop_flags,
68 70 i_ipadm_get_mtu, i_ipadm_get_metric,
69 71 i_ipadm_get_usesrc, i_ipadm_get_forwarding,
70 - i_ipadm_get_ecnsack, i_ipadm_get_hostmodel;
72 + i_ipadm_get_ecnsack, i_ipadm_get_hostmodel,
73 + i_ipadm_get_cc;
71 74
72 75 /*
73 76 * Callback function to set property values. These functions translate the
74 77 * values to a format suitable for kernel consumption, allocates the necessary
75 78 * ioctl buffers and then invokes ioctl().
76 79 */
77 80 static ipadm_pd_setf_t i_ipadm_set_prop, i_ipadm_set_mtu,
78 81 i_ipadm_set_ifprop_flags,
79 82 i_ipadm_set_metric, i_ipadm_set_usesrc,
80 83 i_ipadm_set_forwarding, i_ipadm_set_eprivport,
81 84 i_ipadm_set_ecnsack, i_ipadm_set_hostmodel;
82 85
83 86 /* array of protocols we support */
84 87 static int protocols[] = { MOD_PROTO_IP, MOD_PROTO_RAWIP,
85 88 MOD_PROTO_TCP, MOD_PROTO_UDP,
86 89 MOD_PROTO_SCTP };
87 90
88 91 /*
89 92 * Supported IP protocol properties.
90 93 */
91 94 static ipadm_prop_desc_t ipadm_ip_prop_table[] = {
92 95 { "arp", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 0,
93 96 i_ipadm_set_ifprop_flags, i_ipadm_get_onoff,
94 97 i_ipadm_get_ifprop_flags },
95 98
96 99 { "forwarding", NULL, IPADMPROP_CLASS_MODIF, MOD_PROTO_IPV4, 0,
97 100 i_ipadm_set_forwarding, i_ipadm_get_onoff,
98 101 i_ipadm_get_forwarding },
99 102
100 103 { "metric", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 0,
101 104 i_ipadm_set_metric, NULL, i_ipadm_get_metric },
102 105
103 106 { "mtu", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 0,
104 107 i_ipadm_set_mtu, i_ipadm_get_mtu, i_ipadm_get_mtu },
105 108
106 109 { "exchange_routes", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 0,
107 110 i_ipadm_set_ifprop_flags, i_ipadm_get_onoff,
108 111 i_ipadm_get_ifprop_flags },
109 112
110 113 { "usesrc", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 0,
111 114 i_ipadm_set_usesrc, NULL, i_ipadm_get_usesrc },
112 115
113 116 { "ttl", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_IPV4, 0,
114 117 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
115 118
116 119 { "forwarding", NULL, IPADMPROP_CLASS_MODIF, MOD_PROTO_IPV6, 0,
117 120 i_ipadm_set_forwarding, i_ipadm_get_onoff,
118 121 i_ipadm_get_forwarding },
119 122
120 123 { "hoplimit", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_IPV6, 0,
121 124 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
122 125
123 126 { "metric", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV6, 0,
124 127 i_ipadm_set_metric, NULL, i_ipadm_get_metric },
125 128
126 129 { "mtu", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV6, 0,
127 130 i_ipadm_set_mtu, i_ipadm_get_mtu, i_ipadm_get_mtu },
128 131
129 132 { "nud", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV6, 0,
130 133 i_ipadm_set_ifprop_flags, i_ipadm_get_onoff,
131 134 i_ipadm_get_ifprop_flags },
132 135
133 136 { "exchange_routes", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV6, 0,
134 137 i_ipadm_set_ifprop_flags, i_ipadm_get_onoff,
135 138 i_ipadm_get_ifprop_flags },
136 139
137 140 { "usesrc", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV6, 0,
138 141 i_ipadm_set_usesrc, NULL, i_ipadm_get_usesrc },
139 142
140 143 { "hostmodel", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_IPV6, 0,
141 144 i_ipadm_set_hostmodel, i_ipadm_get_hostmodel,
142 145 i_ipadm_get_hostmodel },
143 146
144 147 { "hostmodel", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_IPV4, 0,
145 148 i_ipadm_set_hostmodel, i_ipadm_get_hostmodel,
|
↓ open down ↓ |
65 lines elided |
↑ open up ↑ |
146 149 i_ipadm_get_hostmodel },
147 150
148 151 { NULL, NULL, 0, 0, 0, NULL, NULL, NULL }
149 152 };
150 153
151 154 /* possible values for TCP properties `ecn' and `sack' */
152 155 static const char *ecn_sack_vals[] = {"never", "passive", "active", NULL};
153 156
154 157 /* Supported TCP protocol properties */
155 158 static ipadm_prop_desc_t ipadm_tcp_prop_table[] = {
159 + { "congestion_control", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
160 + i_ipadm_set_prop, i_ipadm_get_cc, i_ipadm_get_prop },
161 +
156 162 { "ecn", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
157 163 i_ipadm_set_ecnsack, i_ipadm_get_ecnsack, i_ipadm_get_ecnsack },
158 164
159 165 { "extra_priv_ports", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP,
160 166 IPADMPROP_MULVAL, i_ipadm_set_eprivport, i_ipadm_get_prop,
161 167 i_ipadm_get_prop },
162 168
163 169 { "largest_anon_port", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
164 170 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
165 171
166 172 { "max_buf", "_max_buf", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
167 173 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
168 174
169 175 { "recv_buf", "recv_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
170 176 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
171 177
172 178 { "sack", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
173 179 i_ipadm_set_ecnsack, i_ipadm_get_ecnsack, i_ipadm_get_ecnsack },
174 180
175 181 { "send_buf", "send_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
176 182 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
177 183
178 184 { "smallest_anon_port", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
179 185 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
180 186
181 187 { "smallest_nonpriv_port", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP,
182 188 0, i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
183 189
184 190 { NULL, NULL, 0, 0, 0, NULL, NULL, NULL }
185 191 };
186 192
187 193 /* Supported UDP protocol properties */
188 194 static ipadm_prop_desc_t ipadm_udp_prop_table[] = {
189 195 { "extra_priv_ports", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP,
190 196 IPADMPROP_MULVAL, i_ipadm_set_eprivport, i_ipadm_get_prop,
191 197 i_ipadm_get_prop },
192 198
193 199 { "largest_anon_port", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP, 0,
194 200 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
195 201
196 202 { "max_buf", "_max_buf", IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP, 0,
197 203 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
198 204
199 205 { "recv_buf", "recv_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP, 0,
200 206 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
201 207
202 208 { "send_buf", "send_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP, 0,
203 209 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
204 210
205 211 { "smallest_anon_port", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP, 0,
206 212 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
207 213
208 214 { "smallest_nonpriv_port", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP,
209 215 0, i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
210 216
211 217 { NULL, NULL, 0, 0, 0, NULL, NULL, NULL }
212 218 };
213 219
214 220 /* Supported SCTP protocol properties */
215 221 static ipadm_prop_desc_t ipadm_sctp_prop_table[] = {
216 222 { "extra_priv_ports", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP,
217 223 IPADMPROP_MULVAL, i_ipadm_set_eprivport, i_ipadm_get_prop,
218 224 i_ipadm_get_prop },
219 225
220 226 { "largest_anon_port", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP, 0,
221 227 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
222 228
223 229 { "max_buf", "_max_buf", IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP, 0,
224 230 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
225 231
226 232 { "recv_buf", "recv_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP, 0,
227 233 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
228 234
229 235 { "send_buf", "send_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP, 0,
230 236 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
231 237
232 238 { "smallest_anon_port", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP, 0,
233 239 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
234 240
235 241 { "smallest_nonpriv_port", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP,
236 242 0, i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
237 243
238 244 { NULL, NULL, 0, 0, 0, NULL, NULL, NULL }
239 245 };
240 246
241 247 /* Supported ICMP protocol properties */
242 248 static ipadm_prop_desc_t ipadm_icmp_prop_table[] = {
243 249 { "max_buf", "_max_buf", IPADMPROP_CLASS_MODULE, MOD_PROTO_RAWIP, 0,
244 250 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
245 251
246 252 { "recv_buf", "recv_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_RAWIP, 0,
247 253 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
248 254
249 255 { "send_buf", "send_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_RAWIP, 0,
250 256 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
251 257
252 258 { NULL, NULL, 0, 0, 0, NULL, NULL, NULL }
253 259 };
254 260
255 261 /*
256 262 * A dummy private property structure, used while handling private
257 263 * protocol properties (properties not yet supported by libipadm).
258 264 */
259 265 static ipadm_prop_desc_t ipadm_privprop =
260 266 { NULL, NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_NONE, 0,
261 267 i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop };
262 268
263 269 /*
264 270 * Returns the property description table, for the given protocol
265 271 */
266 272 static ipadm_prop_desc_t *
267 273 i_ipadm_get_propdesc_table(uint_t proto)
268 274 {
269 275 switch (proto) {
270 276 case MOD_PROTO_IP:
271 277 case MOD_PROTO_IPV4:
272 278 case MOD_PROTO_IPV6:
273 279 return (ipadm_ip_prop_table);
274 280 case MOD_PROTO_RAWIP:
275 281 return (ipadm_icmp_prop_table);
276 282 case MOD_PROTO_TCP:
277 283 return (ipadm_tcp_prop_table);
278 284 case MOD_PROTO_UDP:
279 285 return (ipadm_udp_prop_table);
280 286 case MOD_PROTO_SCTP:
281 287 return (ipadm_sctp_prop_table);
282 288 }
283 289
284 290 return (NULL);
285 291 }
286 292
287 293 static ipadm_prop_desc_t *
288 294 i_ipadm_get_prop_desc(const char *pname, uint_t proto, int *errp)
289 295 {
290 296 int err = 0;
291 297 boolean_t matched_name = B_FALSE;
292 298 ipadm_prop_desc_t *ipdp = NULL, *ipdtbl;
293 299
294 300 if ((ipdtbl = i_ipadm_get_propdesc_table(proto)) == NULL) {
295 301 err = EINVAL;
296 302 goto ret;
297 303 }
298 304
299 305 for (ipdp = ipdtbl; ipdp->ipd_name != NULL; ipdp++) {
300 306 if (strcmp(pname, ipdp->ipd_name) == 0 ||
301 307 (ipdp->ipd_old_name != NULL &&
302 308 strcmp(pname, ipdp->ipd_old_name) == 0)) {
303 309 matched_name = B_TRUE;
304 310 if (ipdp->ipd_proto == proto)
305 311 break;
306 312 }
307 313 }
308 314
309 315 if (ipdp->ipd_name == NULL) {
310 316 err = ENOENT;
311 317 /* if we matched name, but failed protocol check */
312 318 if (matched_name)
313 319 err = EPROTO;
314 320 ipdp = NULL;
315 321 }
316 322 ret:
317 323 if (errp != NULL)
318 324 *errp = err;
319 325 return (ipdp);
320 326 }
321 327
322 328 char *
323 329 ipadm_proto2str(uint_t proto)
324 330 {
325 331 switch (proto) {
326 332 case MOD_PROTO_IP:
327 333 return ("ip");
328 334 case MOD_PROTO_IPV4:
329 335 return ("ipv4");
330 336 case MOD_PROTO_IPV6:
331 337 return ("ipv6");
332 338 case MOD_PROTO_RAWIP:
333 339 return ("icmp");
334 340 case MOD_PROTO_TCP:
335 341 return ("tcp");
336 342 case MOD_PROTO_UDP:
337 343 return ("udp");
338 344 case MOD_PROTO_SCTP:
339 345 return ("sctp");
340 346 }
341 347
342 348 return (NULL);
343 349 }
344 350
345 351 uint_t
346 352 ipadm_str2proto(const char *protostr)
347 353 {
348 354 if (protostr == NULL)
349 355 return (MOD_PROTO_NONE);
350 356 if (strcmp(protostr, "tcp") == 0)
351 357 return (MOD_PROTO_TCP);
352 358 else if (strcmp(protostr, "udp") == 0)
353 359 return (MOD_PROTO_UDP);
354 360 else if (strcmp(protostr, "ip") == 0)
355 361 return (MOD_PROTO_IP);
356 362 else if (strcmp(protostr, "ipv4") == 0)
357 363 return (MOD_PROTO_IPV4);
358 364 else if (strcmp(protostr, "ipv6") == 0)
359 365 return (MOD_PROTO_IPV6);
360 366 else if (strcmp(protostr, "icmp") == 0)
361 367 return (MOD_PROTO_RAWIP);
362 368 else if (strcmp(protostr, "sctp") == 0)
363 369 return (MOD_PROTO_SCTP);
364 370 else if (strcmp(protostr, "arp") == 0)
365 371 return (MOD_PROTO_IP);
366 372
367 373 return (MOD_PROTO_NONE);
368 374 }
369 375
370 376 /* ARGSUSED */
371 377 static ipadm_status_t
372 378 i_ipadm_set_mtu(ipadm_handle_t iph, const void *arg,
373 379 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
374 380 {
375 381 struct lifreq lifr;
376 382 char *endp;
377 383 uint_t mtu;
378 384 int s;
379 385 const char *ifname = arg;
380 386 char val[MAXPROPVALLEN];
381 387
382 388 /* to reset MTU first retrieve the default MTU and then set it */
383 389 if (flags & IPADM_OPT_DEFAULT) {
384 390 ipadm_status_t status;
385 391 uint_t size = MAXPROPVALLEN;
386 392
387 393 status = i_ipadm_get_prop(iph, arg, pdp, val, &size,
388 394 proto, MOD_PROP_DEFAULT);
389 395 if (status != IPADM_SUCCESS)
390 396 return (status);
391 397 pval = val;
392 398 }
393 399
394 400 errno = 0;
395 401 mtu = (uint_t)strtol(pval, &endp, 10);
396 402 if (errno != 0 || *endp != '\0')
397 403 return (IPADM_INVALID_ARG);
398 404
399 405 bzero(&lifr, sizeof (lifr));
400 406 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
401 407 lifr.lifr_mtu = mtu;
402 408
403 409 s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
404 410 if (ioctl(s, SIOCSLIFMTU, (caddr_t)&lifr) < 0)
405 411 return (ipadm_errno2status(errno));
406 412
407 413 return (IPADM_SUCCESS);
408 414 }
409 415
410 416 /* ARGSUSED */
411 417 static ipadm_status_t
412 418 i_ipadm_set_metric(ipadm_handle_t iph, const void *arg,
413 419 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
414 420 {
415 421 struct lifreq lifr;
416 422 char *endp;
417 423 int metric;
418 424 const char *ifname = arg;
419 425 int s;
420 426
421 427 /* if we are resetting, set the value to its default value */
422 428 if (flags & IPADM_OPT_DEFAULT) {
423 429 metric = DEF_METRIC_VAL;
424 430 } else {
425 431 errno = 0;
426 432 metric = (uint_t)strtol(pval, &endp, 10);
427 433 if (errno != 0 || *endp != '\0')
428 434 return (IPADM_INVALID_ARG);
429 435 }
430 436
431 437 bzero(&lifr, sizeof (lifr));
432 438 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
433 439 lifr.lifr_metric = metric;
434 440
435 441 s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
436 442
437 443 if (ioctl(s, SIOCSLIFMETRIC, (caddr_t)&lifr) < 0)
438 444 return (ipadm_errno2status(errno));
439 445
440 446 return (IPADM_SUCCESS);
441 447 }
442 448
443 449 /* ARGSUSED */
444 450 static ipadm_status_t
445 451 i_ipadm_set_usesrc(ipadm_handle_t iph, const void *arg,
446 452 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
447 453 {
448 454 struct lifreq lifr;
449 455 const char *ifname = arg;
450 456 int s;
451 457 uint_t ifindex = 0;
452 458
453 459 /* if we are resetting, set the value to its default value */
454 460 if (flags & IPADM_OPT_DEFAULT)
455 461 pval = IPADM_NONESTR;
456 462
457 463 /*
458 464 * cannot specify logical interface name. We can also filter out other
459 465 * bogus interface names here itself through i_ipadm_validate_ifname().
460 466 */
461 467 if (strcmp(pval, IPADM_NONESTR) != 0 &&
462 468 !i_ipadm_validate_ifname(iph, pval))
463 469 return (IPADM_INVALID_ARG);
464 470
465 471 bzero(&lifr, sizeof (lifr));
466 472 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
467 473
468 474 s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
469 475
470 476 if (strcmp(pval, IPADM_NONESTR) != 0) {
471 477 if ((ifindex = if_nametoindex(pval)) == 0)
472 478 return (ipadm_errno2status(errno));
473 479 lifr.lifr_index = ifindex;
474 480 } else {
475 481 if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) < 0)
476 482 return (ipadm_errno2status(errno));
477 483 lifr.lifr_index = 0;
478 484 }
479 485 if (ioctl(s, SIOCSLIFUSESRC, (caddr_t)&lifr) < 0)
480 486 return (ipadm_errno2status(errno));
481 487
482 488 return (IPADM_SUCCESS);
483 489 }
484 490
485 491 static struct hostmodel_strval {
486 492 char *esm_str;
487 493 ip_hostmodel_t esm_val;
488 494 } esm_arr[] = {
489 495 {"weak", IP_WEAK_ES},
490 496 {"src-priority", IP_SRC_PRI_ES},
491 497 {"strong", IP_STRONG_ES},
492 498 {"custom", IP_MAXVAL_ES}
493 499 };
494 500
495 501 static ip_hostmodel_t
496 502 i_ipadm_hostmodel_str2val(const char *pval)
497 503 {
498 504 int i;
499 505
500 506 for (i = 0; i < A_CNT(esm_arr); i++) {
501 507 if (esm_arr[i].esm_str != NULL &&
502 508 strcmp(pval, esm_arr[i].esm_str) == 0) {
503 509 return (esm_arr[i].esm_val);
504 510 }
505 511 }
506 512 return (IP_MAXVAL_ES);
507 513 }
508 514
509 515 static char *
510 516 i_ipadm_hostmodel_val2str(ip_hostmodel_t pval)
511 517 {
512 518 int i;
513 519
514 520 for (i = 0; i < A_CNT(esm_arr); i++) {
515 521 if (esm_arr[i].esm_val == pval)
516 522 return (esm_arr[i].esm_str);
517 523 }
518 524 return (NULL);
519 525 }
520 526
521 527 /* ARGSUSED */
522 528 static ipadm_status_t
523 529 i_ipadm_set_hostmodel(ipadm_handle_t iph, const void *arg,
524 530 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
525 531 {
526 532 ip_hostmodel_t hostmodel;
527 533 char val[11]; /* covers uint32_max as a string */
528 534
529 535 if ((flags & IPADM_OPT_DEFAULT) == 0) {
530 536 hostmodel = i_ipadm_hostmodel_str2val(pval);
531 537 if (hostmodel == IP_MAXVAL_ES)
532 538 return (IPADM_INVALID_ARG);
533 539 (void) snprintf(val, sizeof (val), "%d", hostmodel);
534 540 pval = val;
535 541 }
536 542 return (i_ipadm_set_prop(iph, NULL, pdp, pval, proto, flags));
537 543 }
538 544
539 545 /* ARGSUSED */
540 546 static ipadm_status_t
541 547 i_ipadm_get_hostmodel(ipadm_handle_t iph, const void *arg,
542 548 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
543 549 uint_t valtype)
544 550 {
545 551 ip_hostmodel_t hostmodel;
546 552 char *cp;
547 553 size_t nbytes;
548 554 ipadm_status_t status;
549 555
550 556 switch (valtype) {
551 557 case MOD_PROP_PERM:
552 558 nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW);
553 559 break;
554 560 case MOD_PROP_DEFAULT:
555 561 nbytes = snprintf(buf, *bufsize, "weak");
556 562 break;
557 563 case MOD_PROP_ACTIVE:
558 564 status = i_ipadm_get_prop(iph, arg, pdp, buf, bufsize, proto,
559 565 valtype);
560 566 if (status != IPADM_SUCCESS)
561 567 return (status);
562 568 bcopy(buf, &hostmodel, sizeof (hostmodel));
563 569 cp = i_ipadm_hostmodel_val2str(hostmodel);
564 570 nbytes = snprintf(buf, *bufsize, "%s",
565 571 (cp != NULL ? cp : "?"));
566 572 break;
567 573 case MOD_PROP_POSSIBLE:
568 574 nbytes = snprintf(buf, *bufsize, "strong,src-priority,weak");
569 575 break;
570 576 default:
571 577 return (IPADM_INVALID_ARG);
572 578 }
573 579 if (nbytes >= *bufsize) {
574 580 /* insufficient buffer space */
575 581 *bufsize = nbytes + 1;
576 582 return (IPADM_NO_BUFS);
577 583 }
578 584 return (IPADM_SUCCESS);
579 585 }
580 586
581 587 /* ARGSUSED */
582 588 static ipadm_status_t
583 589 i_ipadm_set_ifprop_flags(ipadm_handle_t iph, const void *arg,
584 590 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
585 591 {
586 592 ipadm_status_t status = IPADM_SUCCESS;
587 593 const char *ifname = arg;
588 594 uint64_t on_flags = 0, off_flags = 0;
589 595 boolean_t on = B_FALSE;
590 596 sa_family_t af = (proto == MOD_PROTO_IPV6 ? AF_INET6 : AF_INET);
591 597
592 598 /* if we are resetting, set the value to its default value */
593 599 if (flags & IPADM_OPT_DEFAULT) {
594 600 if (strcmp(pdp->ipd_name, "exchange_routes") == 0 ||
595 601 strcmp(pdp->ipd_name, "arp") == 0 ||
596 602 strcmp(pdp->ipd_name, "nud") == 0) {
597 603 pval = IPADM_ONSTR;
598 604 } else if (strcmp(pdp->ipd_name, "forwarding") == 0) {
599 605 pval = IPADM_OFFSTR;
600 606 } else {
601 607 return (IPADM_PROP_UNKNOWN);
602 608 }
603 609 }
604 610
605 611 if (strcmp(pval, IPADM_ONSTR) == 0)
606 612 on = B_TRUE;
607 613 else if (strcmp(pval, IPADM_OFFSTR) == 0)
608 614 on = B_FALSE;
609 615 else
610 616 return (IPADM_INVALID_ARG);
611 617
612 618 if (strcmp(pdp->ipd_name, "exchange_routes") == 0) {
613 619 if (on)
614 620 off_flags = IFF_NORTEXCH;
615 621 else
616 622 on_flags = IFF_NORTEXCH;
617 623 } else if (strcmp(pdp->ipd_name, "arp") == 0) {
618 624 if (on)
619 625 off_flags = IFF_NOARP;
620 626 else
621 627 on_flags = IFF_NOARP;
622 628 } else if (strcmp(pdp->ipd_name, "nud") == 0) {
623 629 if (on)
624 630 off_flags = IFF_NONUD;
625 631 else
626 632 on_flags = IFF_NONUD;
627 633 } else if (strcmp(pdp->ipd_name, "forwarding") == 0) {
628 634 if (on)
629 635 on_flags = IFF_ROUTER;
630 636 else
631 637 off_flags = IFF_ROUTER;
632 638 }
633 639
634 640 if (on_flags || off_flags) {
635 641 status = i_ipadm_set_flags(iph, ifname, af, on_flags,
636 642 off_flags);
637 643 }
638 644 return (status);
639 645 }
640 646
641 647 /* ARGSUSED */
642 648 static ipadm_status_t
643 649 i_ipadm_set_eprivport(ipadm_handle_t iph, const void *arg,
644 650 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
645 651 {
646 652 nvlist_t *portsnvl = NULL;
647 653 nvpair_t *nvp;
648 654 ipadm_status_t status = IPADM_SUCCESS;
649 655 int err;
650 656 uint_t count = 0;
651 657
652 658 if (flags & IPADM_OPT_DEFAULT) {
653 659 assert(pval == NULL);
654 660 return (i_ipadm_set_prop(iph, arg, pdp, pval, proto, flags));
655 661 }
656 662
657 663 if ((err = ipadm_str2nvlist(pval, &portsnvl, IPADM_NORVAL)) != 0)
658 664 return (ipadm_errno2status(err));
659 665
660 666 /* count the number of ports */
661 667 for (nvp = nvlist_next_nvpair(portsnvl, NULL); nvp != NULL;
662 668 nvp = nvlist_next_nvpair(portsnvl, nvp)) {
663 669 ++count;
664 670 }
665 671
666 672 if (iph->iph_flags & IPH_INIT) {
667 673 flags |= IPADM_OPT_APPEND;
668 674 } else if (count > 1) {
669 675 /*
670 676 * We allow only one port to be added, removed or
671 677 * assigned at a time.
672 678 *
673 679 * However on reboot, while initializing protocol
674 680 * properties, extra_priv_ports might have multiple
675 681 * values. Only in that case we allow setting multiple
676 682 * values.
677 683 */
678 684 nvlist_free(portsnvl);
679 685 return (IPADM_INVALID_ARG);
680 686 }
681 687
682 688 for (nvp = nvlist_next_nvpair(portsnvl, NULL); nvp != NULL;
683 689 nvp = nvlist_next_nvpair(portsnvl, nvp)) {
684 690 status = i_ipadm_set_prop(iph, arg, pdp, nvpair_name(nvp),
685 691 proto, flags);
686 692 if (status != IPADM_SUCCESS)
687 693 break;
688 694 }
689 695 nvlist_free(portsnvl);
690 696 return (status);
691 697 }
692 698
693 699 /* ARGSUSED */
694 700 static ipadm_status_t
695 701 i_ipadm_set_forwarding(ipadm_handle_t iph, const void *arg,
696 702 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
697 703 {
698 704 const char *ifname = arg;
699 705 ipadm_status_t status;
700 706
701 707 /*
702 708 * if interface name is provided, then set forwarding using the
703 709 * IFF_ROUTER flag
704 710 */
705 711 if (ifname != NULL) {
706 712 status = i_ipadm_set_ifprop_flags(iph, ifname, pdp, pval,
707 713 proto, flags);
708 714 } else {
709 715 char *val = NULL;
710 716
711 717 /*
712 718 * if the caller is IPH_LEGACY, `pval' already contains
713 719 * numeric values.
714 720 */
715 721 if (!(flags & IPADM_OPT_DEFAULT) &&
716 722 !(iph->iph_flags & IPH_LEGACY)) {
717 723
718 724 if (strcmp(pval, IPADM_ONSTR) == 0)
719 725 val = "1";
720 726 else if (strcmp(pval, IPADM_OFFSTR) == 0)
721 727 val = "0";
722 728 else
723 729 return (IPADM_INVALID_ARG);
724 730 pval = val;
725 731 }
726 732
727 733 status = i_ipadm_set_prop(iph, ifname, pdp, pval, proto, flags);
728 734 }
729 735
730 736 return (status);
731 737 }
732 738
733 739 /* ARGSUSED */
734 740 static ipadm_status_t
735 741 i_ipadm_set_ecnsack(ipadm_handle_t iph, const void *arg,
736 742 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
737 743 {
738 744 uint_t i;
739 745 char val[MAXPROPVALLEN];
740 746
741 747 /* if IPH_LEGACY is set, `pval' already contains numeric values */
742 748 if (!(flags & IPADM_OPT_DEFAULT) && !(iph->iph_flags & IPH_LEGACY)) {
743 749 for (i = 0; ecn_sack_vals[i] != NULL; i++) {
744 750 if (strcmp(pval, ecn_sack_vals[i]) == 0)
745 751 break;
746 752 }
747 753 if (ecn_sack_vals[i] == NULL)
748 754 return (IPADM_INVALID_ARG);
749 755 (void) snprintf(val, MAXPROPVALLEN, "%d", i);
750 756 pval = val;
751 757 }
752 758
753 759 return (i_ipadm_set_prop(iph, arg, pdp, pval, proto, flags));
754 760 }
755 761
756 762 /* ARGSUSED */
757 763 ipadm_status_t
758 764 i_ipadm_get_ecnsack(ipadm_handle_t iph, const void *arg,
759 765 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
760 766 uint_t valtype)
761 767 {
762 768 ipadm_status_t status = IPADM_SUCCESS;
763 769 uint_t i, nbytes = 0;
764 770
765 771 switch (valtype) {
766 772 case MOD_PROP_POSSIBLE:
767 773 for (i = 0; ecn_sack_vals[i] != NULL; i++) {
768 774 if (i == 0)
769 775 nbytes += snprintf(buf + nbytes,
770 776 *bufsize - nbytes, "%s", ecn_sack_vals[i]);
771 777 else
772 778 nbytes += snprintf(buf + nbytes,
773 779 *bufsize - nbytes, ",%s", ecn_sack_vals[i]);
774 780 if (nbytes >= *bufsize)
775 781 break;
776 782 }
777 783 break;
778 784 case MOD_PROP_PERM:
779 785 case MOD_PROP_DEFAULT:
780 786 case MOD_PROP_ACTIVE:
781 787 status = i_ipadm_get_prop(iph, arg, pdp, buf, bufsize, proto,
782 788 valtype);
783 789
784 790 /*
785 791 * If IPH_LEGACY is set, do not convert the value returned
786 792 * from kernel,
787 793 */
788 794 if (iph->iph_flags & IPH_LEGACY)
789 795 break;
790 796
791 797 /*
792 798 * For current and default value, convert the value returned
793 799 * from kernel to more discrete representation.
794 800 */
795 801 if (status == IPADM_SUCCESS && (valtype == MOD_PROP_ACTIVE ||
796 802 valtype == MOD_PROP_DEFAULT)) {
797 803 i = atoi(buf);
798 804 assert(i < 3);
799 805 nbytes = snprintf(buf, *bufsize, "%s",
800 806 ecn_sack_vals[i]);
801 807 }
802 808 break;
803 809 default:
804 810 return (IPADM_INVALID_ARG);
|
↓ open down ↓ |
639 lines elided |
↑ open up ↑ |
805 811 }
806 812 if (nbytes >= *bufsize) {
807 813 /* insufficient buffer space */
808 814 *bufsize = nbytes + 1;
809 815 return (IPADM_NO_BUFS);
810 816 }
811 817
812 818 return (status);
813 819 }
814 820
821 +/*
822 + * Retrieves the list of possible congestion control algorithms by enumerating
823 + * the modules in /kernel/cc.
824 + */
825 +/* ARGSUSED */
826 +ipadm_status_t
827 +i_ipadm_get_cc(ipadm_handle_t iph, const void *arg, ipadm_prop_desc_t *pdp,
828 + char *buf, uint_t *bufsize, uint_t proto, uint_t valtype)
829 +{
830 + DIR *dir;
831 + struct dirent *ent;
832 + boolean_t first = B_TRUE;
833 + uint_t bytes = 0;
834 +
835 + assert(valtype == MOD_PROP_POSSIBLE);
836 +
837 + /* We assume that all platforms have the same algorithms installed. */
838 + if ((dir = opendir("/kernel/cc")) != NULL) {
839 + while ((ent = readdir(dir)) != NULL) {
840 + /* By convention, modules are named cc_<algo>. */
841 + if (strstr(ent->d_name, "cc_") != NULL) {
842 + bytes += snprintf(buf + bytes,
843 + bytes < *bufsize ? *bufsize - bytes : 0,
844 + "%s%s", first ? "" : ",", ent->d_name + 3);
845 + first = B_FALSE;
846 + }
847 + }
848 + (void) closedir(dir);
849 + }
850 + if (bytes >= *bufsize) {
851 + *bufsize = bytes + 1;
852 + return (IPADM_NO_BUFS);
853 + }
854 + return (IPADM_SUCCESS);
855 +}
856 +
815 857 /* ARGSUSED */
816 858 static ipadm_status_t
817 859 i_ipadm_get_forwarding(ipadm_handle_t iph, const void *arg,
818 860 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
819 861 uint_t valtype)
820 862 {
821 863 const char *ifname = arg;
822 864 ipadm_status_t status = IPADM_SUCCESS;
823 865
824 866 /*
825 867 * if interface name is provided, then get forwarding status using
826 868 * SIOCGLIFFLAGS
827 869 */
828 870 if (ifname != NULL) {
829 871 status = i_ipadm_get_ifprop_flags(iph, ifname, pdp,
830 872 buf, bufsize, pdp->ipd_proto, valtype);
831 873 } else {
832 874 status = i_ipadm_get_prop(iph, ifname, pdp, buf,
833 875 bufsize, proto, valtype);
834 876 /*
835 877 * If IPH_LEGACY is set, do not convert the value returned
836 878 * from kernel,
837 879 */
838 880 if (iph->iph_flags & IPH_LEGACY)
839 881 goto ret;
840 882 if (status == IPADM_SUCCESS && (valtype == MOD_PROP_ACTIVE ||
841 883 valtype == MOD_PROP_DEFAULT)) {
842 884 uint_t val = atoi(buf);
843 885
844 886 (void) snprintf(buf, *bufsize,
845 887 (val == 1 ? IPADM_ONSTR : IPADM_OFFSTR));
846 888 }
847 889 }
848 890
849 891 ret:
850 892 return (status);
851 893 }
852 894
853 895 /* ARGSUSED */
854 896 static ipadm_status_t
855 897 i_ipadm_get_mtu(ipadm_handle_t iph, const void *arg,
856 898 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
857 899 uint_t valtype)
858 900 {
859 901 struct lifreq lifr;
860 902 const char *ifname = arg;
861 903 size_t nbytes;
862 904 int s;
863 905
864 906 switch (valtype) {
865 907 case MOD_PROP_PERM:
866 908 nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW);
867 909 break;
868 910 case MOD_PROP_DEFAULT:
869 911 case MOD_PROP_POSSIBLE:
870 912 return (i_ipadm_get_prop(iph, arg, pdp, buf, bufsize,
871 913 proto, valtype));
872 914 case MOD_PROP_ACTIVE:
873 915 bzero(&lifr, sizeof (lifr));
874 916 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
875 917 s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
876 918
877 919 if (ioctl(s, SIOCGLIFMTU, (caddr_t)&lifr) < 0)
878 920 return (ipadm_errno2status(errno));
879 921 nbytes = snprintf(buf, *bufsize, "%u", lifr.lifr_mtu);
880 922 break;
881 923 default:
882 924 return (IPADM_INVALID_ARG);
883 925 }
884 926 if (nbytes >= *bufsize) {
885 927 /* insufficient buffer space */
886 928 *bufsize = nbytes + 1;
887 929 return (IPADM_NO_BUFS);
888 930 }
889 931 return (IPADM_SUCCESS);
890 932 }
891 933
892 934 /* ARGSUSED */
893 935 static ipadm_status_t
894 936 i_ipadm_get_metric(ipadm_handle_t iph, const void *arg,
895 937 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
896 938 uint_t valtype)
897 939 {
898 940 struct lifreq lifr;
899 941 const char *ifname = arg;
900 942 size_t nbytes;
901 943 int s, val;
902 944
903 945 switch (valtype) {
904 946 case MOD_PROP_PERM:
905 947 val = MOD_PROP_PERM_RW;
906 948 break;
907 949 case MOD_PROP_DEFAULT:
908 950 val = DEF_METRIC_VAL;
909 951 break;
910 952 case MOD_PROP_ACTIVE:
911 953 bzero(&lifr, sizeof (lifr));
912 954 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
913 955
914 956 s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
915 957 if (ioctl(s, SIOCGLIFMETRIC, (caddr_t)&lifr) < 0)
916 958 return (ipadm_errno2status(errno));
917 959 val = lifr.lifr_metric;
918 960 break;
919 961 default:
920 962 return (IPADM_INVALID_ARG);
921 963 }
922 964 nbytes = snprintf(buf, *bufsize, "%d", val);
923 965 if (nbytes >= *bufsize) {
924 966 /* insufficient buffer space */
925 967 *bufsize = nbytes + 1;
926 968 return (IPADM_NO_BUFS);
927 969 }
928 970
929 971 return (IPADM_SUCCESS);
930 972 }
931 973
932 974 /* ARGSUSED */
933 975 static ipadm_status_t
934 976 i_ipadm_get_usesrc(ipadm_handle_t iph, const void *arg,
935 977 ipadm_prop_desc_t *ipd, char *buf, uint_t *bufsize, uint_t proto,
936 978 uint_t valtype)
937 979 {
938 980 struct lifreq lifr;
939 981 const char *ifname = arg;
940 982 int s;
941 983 char if_name[IF_NAMESIZE];
942 984 size_t nbytes;
943 985
944 986 switch (valtype) {
945 987 case MOD_PROP_PERM:
946 988 nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW);
947 989 break;
948 990 case MOD_PROP_DEFAULT:
949 991 nbytes = snprintf(buf, *bufsize, "%s", IPADM_NONESTR);
950 992 break;
951 993 case MOD_PROP_ACTIVE:
952 994 bzero(&lifr, sizeof (lifr));
953 995 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
954 996
955 997 s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
956 998 if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) < 0)
957 999 return (ipadm_errno2status(errno));
958 1000 if (lifr.lifr_index == 0) {
959 1001 /* no src address was set, so print 'none' */
960 1002 (void) strlcpy(if_name, IPADM_NONESTR,
961 1003 sizeof (if_name));
962 1004 } else if (if_indextoname(lifr.lifr_index, if_name) == NULL) {
963 1005 return (ipadm_errno2status(errno));
964 1006 }
965 1007 nbytes = snprintf(buf, *bufsize, "%s", if_name);
966 1008 break;
967 1009 default:
968 1010 return (IPADM_INVALID_ARG);
969 1011 }
970 1012 if (nbytes >= *bufsize) {
971 1013 /* insufficient buffer space */
972 1014 *bufsize = nbytes + 1;
973 1015 return (IPADM_NO_BUFS);
974 1016 }
975 1017 return (IPADM_SUCCESS);
976 1018 }
977 1019
978 1020 /* ARGSUSED */
979 1021 static ipadm_status_t
980 1022 i_ipadm_get_ifprop_flags(ipadm_handle_t iph, const void *arg,
981 1023 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
982 1024 uint_t valtype)
983 1025 {
984 1026 uint64_t intf_flags;
985 1027 char *val;
986 1028 size_t nbytes;
987 1029 const char *ifname = arg;
988 1030 sa_family_t af;
989 1031 ipadm_status_t status = IPADM_SUCCESS;
990 1032
991 1033 switch (valtype) {
992 1034 case MOD_PROP_PERM:
993 1035 nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW);
994 1036 break;
995 1037 case MOD_PROP_DEFAULT:
996 1038 if (strcmp(pdp->ipd_name, "exchange_routes") == 0 ||
997 1039 strcmp(pdp->ipd_name, "arp") == 0 ||
998 1040 strcmp(pdp->ipd_name, "nud") == 0) {
999 1041 val = IPADM_ONSTR;
1000 1042 } else if (strcmp(pdp->ipd_name, "forwarding") == 0) {
1001 1043 val = IPADM_OFFSTR;
1002 1044 } else {
1003 1045 return (IPADM_PROP_UNKNOWN);
1004 1046 }
1005 1047 nbytes = snprintf(buf, *bufsize, "%s", val);
1006 1048 break;
1007 1049 case MOD_PROP_ACTIVE:
1008 1050 af = (proto == MOD_PROTO_IPV6 ? AF_INET6 : AF_INET);
1009 1051 status = i_ipadm_get_flags(iph, ifname, af, &intf_flags);
1010 1052 if (status != IPADM_SUCCESS)
1011 1053 return (status);
1012 1054
1013 1055 val = IPADM_OFFSTR;
1014 1056 if (strcmp(pdp->ipd_name, "exchange_routes") == 0) {
1015 1057 if (!(intf_flags & IFF_NORTEXCH))
1016 1058 val = IPADM_ONSTR;
1017 1059 } else if (strcmp(pdp->ipd_name, "forwarding") == 0) {
1018 1060 if (intf_flags & IFF_ROUTER)
1019 1061 val = IPADM_ONSTR;
1020 1062 } else if (strcmp(pdp->ipd_name, "arp") == 0) {
1021 1063 if (!(intf_flags & IFF_NOARP))
1022 1064 val = IPADM_ONSTR;
1023 1065 } else if (strcmp(pdp->ipd_name, "nud") == 0) {
1024 1066 if (!(intf_flags & IFF_NONUD))
1025 1067 val = IPADM_ONSTR;
1026 1068 }
1027 1069 nbytes = snprintf(buf, *bufsize, "%s", val);
1028 1070 break;
1029 1071 default:
1030 1072 return (IPADM_INVALID_ARG);
1031 1073 }
1032 1074 if (nbytes >= *bufsize) {
1033 1075 /* insufficient buffer space */
1034 1076 *bufsize = nbytes + 1;
1035 1077 status = IPADM_NO_BUFS;
1036 1078 }
1037 1079
1038 1080 return (status);
1039 1081 }
1040 1082
1041 1083 static void
1042 1084 i_ipadm_perm2str(char *buf, uint_t *bufsize)
1043 1085 {
1044 1086 uint_t perm = atoi(buf);
1045 1087
1046 1088 (void) snprintf(buf, *bufsize, "%c%c",
1047 1089 ((perm & MOD_PROP_PERM_READ) != 0) ? 'r' : '-',
1048 1090 ((perm & MOD_PROP_PERM_WRITE) != 0) ? 'w' : '-');
1049 1091 }
1050 1092
1051 1093 /* ARGSUSED */
1052 1094 static ipadm_status_t
1053 1095 i_ipadm_get_prop(ipadm_handle_t iph, const void *arg,
1054 1096 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
1055 1097 uint_t valtype)
1056 1098 {
1057 1099 ipadm_status_t status = IPADM_SUCCESS;
1058 1100 const char *ifname = arg;
1059 1101 mod_ioc_prop_t *mip;
1060 1102 char *pname = pdp->ipd_name;
1061 1103 uint_t iocsize;
1062 1104
1063 1105 /* allocate sufficient ioctl buffer to retrieve value */
1064 1106 iocsize = sizeof (mod_ioc_prop_t) + *bufsize - 1;
1065 1107 if ((mip = calloc(1, iocsize)) == NULL)
1066 1108 return (IPADM_NO_BUFS);
1067 1109
1068 1110 mip->mpr_version = MOD_PROP_VERSION;
1069 1111 mip->mpr_flags = valtype;
1070 1112 mip->mpr_proto = proto;
1071 1113 if (ifname != NULL) {
1072 1114 (void) strlcpy(mip->mpr_ifname, ifname,
1073 1115 sizeof (mip->mpr_ifname));
1074 1116 }
1075 1117 (void) strlcpy(mip->mpr_name, pname, sizeof (mip->mpr_name));
1076 1118 mip->mpr_valsize = *bufsize;
1077 1119
1078 1120 if (i_ipadm_strioctl(iph->iph_sock, SIOCGETPROP, (char *)mip,
1079 1121 iocsize) < 0) {
1080 1122 if (errno == ENOENT)
1081 1123 status = IPADM_PROP_UNKNOWN;
1082 1124 else
1083 1125 status = ipadm_errno2status(errno);
1084 1126 } else {
1085 1127 bcopy(mip->mpr_val, buf, *bufsize);
1086 1128 }
1087 1129
1088 1130 free(mip);
1089 1131 return (status);
1090 1132 }
1091 1133
1092 1134 /*
1093 1135 * Populates the ipmgmt_prop_arg_t based on the class of property.
1094 1136 *
1095 1137 * For private protocol properties, while persisting information in ipadm
1096 1138 * data store, to ensure there is no collision of namespace between ipadm
1097 1139 * private nvpair names (which also starts with '_', see ipadm_ipmgmt.h)
1098 1140 * and private protocol property names, we will prepend IPADM_PRIV_PROP_PREFIX
1099 1141 * to property names.
1100 1142 */
1101 1143 static void
1102 1144 i_ipadm_populate_proparg(ipmgmt_prop_arg_t *pargp, ipadm_prop_desc_t *pdp,
1103 1145 const char *pval, const void *object)
1104 1146 {
1105 1147 const struct ipadm_addrobj_s *ipaddr;
1106 1148 uint_t class = pdp->ipd_class;
1107 1149 uint_t proto = pdp->ipd_proto;
1108 1150
1109 1151 (void) strlcpy(pargp->ia_pname, pdp->ipd_name,
1110 1152 sizeof (pargp->ia_pname));
1111 1153 if (pval != NULL)
1112 1154 (void) strlcpy(pargp->ia_pval, pval, sizeof (pargp->ia_pval));
1113 1155
1114 1156 switch (class) {
1115 1157 case IPADMPROP_CLASS_MODULE:
1116 1158 /* if it's a private property then add the prefix. */
1117 1159 if (pdp->ipd_name[0] == '_') {
1118 1160 (void) snprintf(pargp->ia_pname,
1119 1161 sizeof (pargp->ia_pname), "_%s", pdp->ipd_name);
1120 1162 }
1121 1163 (void) strlcpy(pargp->ia_module, object,
1122 1164 sizeof (pargp->ia_module));
1123 1165 break;
1124 1166 case IPADMPROP_CLASS_MODIF:
1125 1167 /* check if object is protostr or an ifname */
1126 1168 if (ipadm_str2proto(object) != MOD_PROTO_NONE) {
1127 1169 (void) strlcpy(pargp->ia_module, object,
1128 1170 sizeof (pargp->ia_module));
1129 1171 break;
1130 1172 }
1131 1173 /* it's an interface property, fall through */
1132 1174 /* FALLTHRU */
1133 1175 case IPADMPROP_CLASS_IF:
1134 1176 (void) strlcpy(pargp->ia_ifname, object,
1135 1177 sizeof (pargp->ia_ifname));
1136 1178 (void) strlcpy(pargp->ia_module, ipadm_proto2str(proto),
1137 1179 sizeof (pargp->ia_module));
1138 1180 break;
1139 1181 case IPADMPROP_CLASS_ADDR:
1140 1182 ipaddr = object;
1141 1183 (void) strlcpy(pargp->ia_ifname, ipaddr->ipadm_ifname,
1142 1184 sizeof (pargp->ia_ifname));
1143 1185 (void) strlcpy(pargp->ia_aobjname, ipaddr->ipadm_aobjname,
1144 1186 sizeof (pargp->ia_aobjname));
1145 1187 break;
1146 1188 }
1147 1189 }
1148 1190
1149 1191 /*
1150 1192 * Common function to retrieve property value for a given interface `ifname' or
1151 1193 * for a given protocol `proto'. The property name is in `pname'.
1152 1194 *
1153 1195 * `valtype' determines the type of value that will be retrieved.
1154 1196 * IPADM_OPT_ACTIVE - current value of the property (active config)
1155 1197 * IPADM_OPT_PERSIST - value of the property from persistent store
1156 1198 * IPADM_OPT_DEFAULT - default hard coded value (boot-time value)
1157 1199 * IPADM_OPT_PERM - read/write permissions for the value
1158 1200 * IPADM_OPT_POSSIBLE - range of values
1159 1201 */
1160 1202 static ipadm_status_t
1161 1203 i_ipadm_getprop_common(ipadm_handle_t iph, const char *ifname,
1162 1204 const char *pname, char *buf, uint_t *bufsize, uint_t proto,
1163 1205 uint_t valtype)
1164 1206 {
1165 1207 ipadm_status_t status = IPADM_SUCCESS;
1166 1208 ipadm_prop_desc_t *pdp;
1167 1209 char priv_propname[MAXPROPNAMELEN];
1168 1210 boolean_t is_if = (ifname != NULL);
1169 1211 int err = 0;
1170 1212
1171 1213 pdp = i_ipadm_get_prop_desc(pname, proto, &err);
1172 1214 if (err == EPROTO)
1173 1215 return (IPADM_BAD_PROTOCOL);
1174 1216 /* there are no private interface properties */
1175 1217 if (is_if && err == ENOENT)
1176 1218 return (IPADM_PROP_UNKNOWN);
1177 1219
1178 1220 if (pdp != NULL) {
1179 1221 /*
1180 1222 * check whether the property can be
1181 1223 * applied on an interface
1182 1224 */
1183 1225 if (is_if && !(pdp->ipd_class & IPADMPROP_CLASS_IF))
1184 1226 return (IPADM_INVALID_ARG);
1185 1227 /*
1186 1228 * check whether the property can be
1187 1229 * applied on a module
1188 1230 */
1189 1231 if (!is_if && !(pdp->ipd_class & IPADMPROP_CLASS_MODULE))
1190 1232 return (IPADM_INVALID_ARG);
1191 1233
1192 1234 } else {
1193 1235 /* private protocol properties, pass it to kernel directly */
1194 1236 pdp = &ipadm_privprop;
1195 1237 (void) strlcpy(priv_propname, pname, sizeof (priv_propname));
1196 1238 pdp->ipd_name = priv_propname;
1197 1239 }
1198 1240
1199 1241 switch (valtype) {
1200 1242 case IPADM_OPT_PERM:
1201 1243 status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto,
1202 1244 MOD_PROP_PERM);
1203 1245 if (status == IPADM_SUCCESS)
1204 1246 i_ipadm_perm2str(buf, bufsize);
1205 1247 break;
1206 1248 case IPADM_OPT_ACTIVE:
1207 1249 status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto,
1208 1250 MOD_PROP_ACTIVE);
1209 1251 break;
1210 1252 case IPADM_OPT_DEFAULT:
1211 1253 status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto,
1212 1254 MOD_PROP_DEFAULT);
1213 1255 break;
1214 1256 case IPADM_OPT_POSSIBLE:
1215 1257 if (pdp->ipd_get_range != NULL) {
1216 1258 status = pdp->ipd_get_range(iph, ifname, pdp, buf,
1217 1259 bufsize, proto, MOD_PROP_POSSIBLE);
1218 1260 break;
1219 1261 }
1220 1262 buf[0] = '\0';
1221 1263 break;
1222 1264 case IPADM_OPT_PERSIST:
1223 1265 /* retrieve from database */
1224 1266 if (is_if)
1225 1267 status = i_ipadm_get_persist_propval(iph, pdp, buf,
1226 1268 bufsize, ifname);
1227 1269 else
1228 1270 status = i_ipadm_get_persist_propval(iph, pdp, buf,
1229 1271 bufsize, ipadm_proto2str(proto));
1230 1272 break;
1231 1273 default:
1232 1274 status = IPADM_INVALID_ARG;
1233 1275 break;
1234 1276 }
1235 1277 return (status);
1236 1278 }
1237 1279
1238 1280 /*
1239 1281 * Get protocol property of the specified protocol.
1240 1282 */
1241 1283 ipadm_status_t
1242 1284 ipadm_get_prop(ipadm_handle_t iph, const char *pname, char *buf,
1243 1285 uint_t *bufsize, uint_t proto, uint_t valtype)
1244 1286 {
1245 1287 /*
1246 1288 * validate the arguments of the function.
1247 1289 */
1248 1290 if (iph == NULL || pname == NULL || buf == NULL ||
1249 1291 bufsize == NULL || *bufsize == 0) {
1250 1292 return (IPADM_INVALID_ARG);
1251 1293 }
1252 1294 /*
1253 1295 * Do we support this proto, if not return error.
1254 1296 */
1255 1297 if (ipadm_proto2str(proto) == NULL)
1256 1298 return (IPADM_NOTSUP);
1257 1299
1258 1300 return (i_ipadm_getprop_common(iph, NULL, pname, buf, bufsize,
1259 1301 proto, valtype));
1260 1302 }
1261 1303
1262 1304 /*
1263 1305 * Get interface property of the specified interface.
1264 1306 */
1265 1307 ipadm_status_t
1266 1308 ipadm_get_ifprop(ipadm_handle_t iph, const char *ifname, const char *pname,
1267 1309 char *buf, uint_t *bufsize, uint_t proto, uint_t valtype)
1268 1310 {
1269 1311 /* validate the arguments of the function. */
1270 1312 if (iph == NULL || pname == NULL || buf == NULL ||
1271 1313 bufsize == NULL || *bufsize == 0) {
1272 1314 return (IPADM_INVALID_ARG);
1273 1315 }
1274 1316
1275 1317 /* Do we support this proto, if not return error. */
1276 1318 if (ipadm_proto2str(proto) == NULL)
1277 1319 return (IPADM_NOTSUP);
1278 1320
1279 1321 /*
1280 1322 * check if interface name is provided for interface property and
1281 1323 * is valid.
1282 1324 */
1283 1325 if (!i_ipadm_validate_ifname(iph, ifname))
1284 1326 return (IPADM_INVALID_ARG);
1285 1327
1286 1328 return (i_ipadm_getprop_common(iph, ifname, pname, buf, bufsize,
1287 1329 proto, valtype));
1288 1330 }
1289 1331
1290 1332 /*
1291 1333 * Allocates sufficient ioctl buffers and copies property name and the
1292 1334 * value, among other things. If the flag IPADM_OPT_DEFAULT is set, then
1293 1335 * `pval' will be NULL and it instructs the kernel to reset the current
1294 1336 * value to property's default value.
1295 1337 */
1296 1338 static ipadm_status_t
1297 1339 i_ipadm_set_prop(ipadm_handle_t iph, const void *arg,
1298 1340 ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
1299 1341 {
1300 1342 ipadm_status_t status = IPADM_SUCCESS;
1301 1343 const char *ifname = arg;
1302 1344 mod_ioc_prop_t *mip;
1303 1345 char *pname = pdp->ipd_name;
1304 1346 uint_t valsize, iocsize;
1305 1347 uint_t iocflags = 0;
1306 1348
1307 1349 if (flags & IPADM_OPT_DEFAULT) {
1308 1350 iocflags |= MOD_PROP_DEFAULT;
1309 1351 } else if (flags & IPADM_OPT_ACTIVE) {
1310 1352 iocflags |= MOD_PROP_ACTIVE;
1311 1353 if (flags & IPADM_OPT_APPEND)
1312 1354 iocflags |= MOD_PROP_APPEND;
1313 1355 else if (flags & IPADM_OPT_REMOVE)
1314 1356 iocflags |= MOD_PROP_REMOVE;
1315 1357 }
1316 1358
1317 1359 if (pval != NULL) {
1318 1360 valsize = strlen(pval);
1319 1361 iocsize = sizeof (mod_ioc_prop_t) + valsize - 1;
1320 1362 } else {
1321 1363 valsize = 0;
1322 1364 iocsize = sizeof (mod_ioc_prop_t);
1323 1365 }
1324 1366
1325 1367 if ((mip = calloc(1, iocsize)) == NULL)
1326 1368 return (IPADM_NO_BUFS);
1327 1369
1328 1370 mip->mpr_version = MOD_PROP_VERSION;
1329 1371 mip->mpr_flags = iocflags;
1330 1372 mip->mpr_proto = proto;
1331 1373 if (ifname != NULL) {
1332 1374 (void) strlcpy(mip->mpr_ifname, ifname,
1333 1375 sizeof (mip->mpr_ifname));
1334 1376 }
1335 1377
1336 1378 (void) strlcpy(mip->mpr_name, pname, sizeof (mip->mpr_name));
1337 1379 mip->mpr_valsize = valsize;
1338 1380 if (pval != NULL)
1339 1381 bcopy(pval, mip->mpr_val, valsize);
1340 1382
1341 1383 if (i_ipadm_strioctl(iph->iph_sock, SIOCSETPROP, (char *)mip,
1342 1384 iocsize) < 0) {
1343 1385 if (errno == ENOENT)
1344 1386 status = IPADM_PROP_UNKNOWN;
1345 1387 else
1346 1388 status = ipadm_errno2status(errno);
1347 1389 }
1348 1390 free(mip);
1349 1391 return (status);
1350 1392 }
1351 1393
1352 1394 /*
1353 1395 * Common function for modifying both protocol/interface property.
1354 1396 *
1355 1397 * If:
1356 1398 * IPADM_OPT_PERSIST is set then the value is persisted.
1357 1399 * IPADM_OPT_DEFAULT is set then the default value for the property will
1358 1400 * be applied.
1359 1401 */
1360 1402 static ipadm_status_t
1361 1403 i_ipadm_setprop_common(ipadm_handle_t iph, const char *ifname,
1362 1404 const char *pname, const char *buf, uint_t proto, uint_t pflags)
1363 1405 {
1364 1406 ipadm_status_t status = IPADM_SUCCESS;
1365 1407 boolean_t persist = (pflags & IPADM_OPT_PERSIST);
1366 1408 boolean_t reset = (pflags & IPADM_OPT_DEFAULT);
1367 1409 ipadm_prop_desc_t *pdp;
1368 1410 boolean_t is_if = (ifname != NULL);
1369 1411 char priv_propname[MAXPROPNAMELEN];
1370 1412 int err = 0;
1371 1413
1372 1414 /* Check that property value is within the allowed size */
1373 1415 if (!reset && strnlen(buf, MAXPROPVALLEN) >= MAXPROPVALLEN)
1374 1416 return (IPADM_INVALID_ARG);
1375 1417
1376 1418 pdp = i_ipadm_get_prop_desc(pname, proto, &err);
1377 1419 if (err == EPROTO)
1378 1420 return (IPADM_BAD_PROTOCOL);
1379 1421 /* there are no private interface properties */
1380 1422 if (is_if && err == ENOENT)
1381 1423 return (IPADM_PROP_UNKNOWN);
1382 1424
1383 1425 if (pdp != NULL) {
1384 1426 /* do some sanity checks */
1385 1427 if (is_if) {
1386 1428 if (!(pdp->ipd_class & IPADMPROP_CLASS_IF))
1387 1429 return (IPADM_INVALID_ARG);
1388 1430 } else {
1389 1431 if (!(pdp->ipd_class & IPADMPROP_CLASS_MODULE))
1390 1432 return (IPADM_INVALID_ARG);
1391 1433 }
1392 1434 /*
1393 1435 * if the property is not multi-valued and IPADM_OPT_APPEND or
1394 1436 * IPADM_OPT_REMOVE is specified, return IPADM_INVALID_ARG.
1395 1437 */
1396 1438 if (!(pdp->ipd_flags & IPADMPROP_MULVAL) && (pflags &
1397 1439 (IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) {
1398 1440 return (IPADM_INVALID_ARG);
1399 1441 }
1400 1442 } else {
1401 1443 /* private protocol property, pass it to kernel directly */
1402 1444 pdp = &ipadm_privprop;
1403 1445 (void) strlcpy(priv_propname, pname, sizeof (priv_propname));
1404 1446 pdp->ipd_name = priv_propname;
1405 1447 }
1406 1448
1407 1449 status = pdp->ipd_set(iph, ifname, pdp, buf, proto, pflags);
1408 1450 if (status != IPADM_SUCCESS)
1409 1451 return (status);
1410 1452
1411 1453 if (persist) {
1412 1454 if (is_if)
1413 1455 status = i_ipadm_persist_propval(iph, pdp, buf, ifname,
1414 1456 pflags);
1415 1457 else
1416 1458 status = i_ipadm_persist_propval(iph, pdp, buf,
1417 1459 ipadm_proto2str(proto), pflags);
1418 1460 }
1419 1461 return (status);
1420 1462 }
1421 1463
1422 1464 /*
1423 1465 * Sets the property value of the specified interface
1424 1466 */
1425 1467 ipadm_status_t
1426 1468 ipadm_set_ifprop(ipadm_handle_t iph, const char *ifname, const char *pname,
1427 1469 const char *buf, uint_t proto, uint_t pflags)
1428 1470 {
1429 1471 boolean_t reset = (pflags & IPADM_OPT_DEFAULT);
1430 1472 ipadm_status_t status;
1431 1473
1432 1474 /* check for solaris.network.interface.config authorization */
1433 1475 if (!ipadm_check_auth())
1434 1476 return (IPADM_EAUTH);
1435 1477 /*
1436 1478 * validate the arguments of the function.
1437 1479 */
1438 1480 if (iph == NULL || pname == NULL || (!reset && buf == NULL) ||
1439 1481 pflags == 0 || pflags == IPADM_OPT_PERSIST ||
1440 1482 (pflags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_DEFAULT))) {
1441 1483 return (IPADM_INVALID_ARG);
1442 1484 }
1443 1485
1444 1486 /*
1445 1487 * Do we support this protocol, if not return error.
1446 1488 */
1447 1489 if (ipadm_proto2str(proto) == NULL)
1448 1490 return (IPADM_NOTSUP);
1449 1491
1450 1492 /*
1451 1493 * Validate the interface and check if a persistent
1452 1494 * operation is performed on a temporary object.
1453 1495 */
1454 1496 status = i_ipadm_validate_if(iph, ifname, proto, pflags);
1455 1497 if (status != IPADM_SUCCESS)
1456 1498 return (status);
1457 1499
1458 1500 return (i_ipadm_setprop_common(iph, ifname, pname, buf, proto,
1459 1501 pflags));
1460 1502 }
1461 1503
1462 1504 /*
1463 1505 * Sets the property value of the specified protocol.
1464 1506 */
1465 1507 ipadm_status_t
1466 1508 ipadm_set_prop(ipadm_handle_t iph, const char *pname, const char *buf,
1467 1509 uint_t proto, uint_t pflags)
1468 1510 {
1469 1511 boolean_t reset = (pflags & IPADM_OPT_DEFAULT);
1470 1512
1471 1513 /* check for solaris.network.interface.config authorization */
1472 1514 if (!ipadm_check_auth())
1473 1515 return (IPADM_EAUTH);
1474 1516 /*
1475 1517 * validate the arguments of the function.
1476 1518 */
1477 1519 if (iph == NULL || pname == NULL ||(!reset && buf == NULL) ||
1478 1520 pflags == 0 || pflags == IPADM_OPT_PERSIST ||
1479 1521 (pflags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_DEFAULT|
1480 1522 IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) {
1481 1523 return (IPADM_INVALID_ARG);
1482 1524 }
1483 1525
1484 1526 /*
1485 1527 * Do we support this proto, if not return error.
1486 1528 */
1487 1529 if (ipadm_proto2str(proto) == NULL)
1488 1530 return (IPADM_NOTSUP);
1489 1531
1490 1532 return (i_ipadm_setprop_common(iph, NULL, pname, buf, proto,
1491 1533 pflags));
1492 1534 }
1493 1535
1494 1536 /* helper function for ipadm_walk_proptbl */
1495 1537 static void
1496 1538 i_ipadm_walk_proptbl(ipadm_prop_desc_t *pdtbl, uint_t proto, uint_t class,
1497 1539 ipadm_prop_wfunc_t *func, void *arg)
1498 1540 {
1499 1541 ipadm_prop_desc_t *pdp;
1500 1542
1501 1543 for (pdp = pdtbl; pdp->ipd_name != NULL; pdp++) {
1502 1544 if (!(pdp->ipd_class & class))
1503 1545 continue;
1504 1546
1505 1547 if (proto != MOD_PROTO_NONE && !(pdp->ipd_proto & proto))
1506 1548 continue;
1507 1549
1508 1550 /*
1509 1551 * we found a class specific match, call the
1510 1552 * user callback function.
1511 1553 */
1512 1554 if (func(arg, pdp->ipd_name, pdp->ipd_proto) == B_FALSE)
1513 1555 break;
1514 1556 }
1515 1557 }
1516 1558
1517 1559 /*
1518 1560 * Walks through all the properties, for a given protocol and property class
1519 1561 * (protocol or interface).
1520 1562 *
1521 1563 * Further if proto == MOD_PROTO_NONE, then it walks through all the supported
1522 1564 * protocol property tables.
1523 1565 */
1524 1566 ipadm_status_t
1525 1567 ipadm_walk_proptbl(uint_t proto, uint_t class, ipadm_prop_wfunc_t *func,
1526 1568 void *arg)
1527 1569 {
1528 1570 ipadm_prop_desc_t *pdtbl;
1529 1571 ipadm_status_t status = IPADM_SUCCESS;
1530 1572 int i;
1531 1573 int count = A_CNT(protocols);
1532 1574
1533 1575 if (func == NULL)
1534 1576 return (IPADM_INVALID_ARG);
1535 1577
1536 1578 switch (class) {
1537 1579 case IPADMPROP_CLASS_ADDR:
1538 1580 pdtbl = ipadm_addrprop_table;
1539 1581 break;
1540 1582 case IPADMPROP_CLASS_IF:
1541 1583 case IPADMPROP_CLASS_MODULE:
1542 1584 pdtbl = i_ipadm_get_propdesc_table(proto);
1543 1585 if (pdtbl == NULL && proto != MOD_PROTO_NONE)
1544 1586 return (IPADM_INVALID_ARG);
1545 1587 break;
1546 1588 default:
1547 1589 return (IPADM_INVALID_ARG);
1548 1590 }
1549 1591
1550 1592 if (pdtbl != NULL) {
1551 1593 /*
1552 1594 * proto will be MOD_PROTO_NONE in the case of
1553 1595 * IPADMPROP_CLASS_ADDR.
1554 1596 */
1555 1597 i_ipadm_walk_proptbl(pdtbl, proto, class, func, arg);
1556 1598 } else {
1557 1599 /* Walk thru all the protocol tables, we support */
1558 1600 for (i = 0; i < count; i++) {
1559 1601 pdtbl = i_ipadm_get_propdesc_table(protocols[i]);
1560 1602 i_ipadm_walk_proptbl(pdtbl, protocols[i], class, func,
1561 1603 arg);
1562 1604 }
1563 1605 }
1564 1606 return (status);
1565 1607 }
1566 1608
1567 1609 /*
1568 1610 * Given a property name, walks through all the instances of a property name.
1569 1611 * Some properties have two instances one for v4 interfaces and another for v6
1570 1612 * interfaces. For example: MTU. MTU can have different values for v4 and v6.
1571 1613 * Therefore there are two properties for 'MTU'.
1572 1614 *
1573 1615 * This function invokes `func' for every instance of property `pname'
1574 1616 */
1575 1617 ipadm_status_t
1576 1618 ipadm_walk_prop(const char *pname, uint_t proto, uint_t class,
1577 1619 ipadm_prop_wfunc_t *func, void *arg)
1578 1620 {
1579 1621 ipadm_prop_desc_t *pdtbl, *pdp;
1580 1622 ipadm_status_t status = IPADM_SUCCESS;
1581 1623 boolean_t matched = B_FALSE;
1582 1624
1583 1625 if (pname == NULL || func == NULL)
1584 1626 return (IPADM_INVALID_ARG);
1585 1627
1586 1628 switch (class) {
1587 1629 case IPADMPROP_CLASS_ADDR:
1588 1630 pdtbl = ipadm_addrprop_table;
1589 1631 break;
1590 1632 case IPADMPROP_CLASS_IF:
1591 1633 case IPADMPROP_CLASS_MODULE:
1592 1634 pdtbl = i_ipadm_get_propdesc_table(proto);
1593 1635 break;
1594 1636 default:
1595 1637 return (IPADM_INVALID_ARG);
1596 1638 }
1597 1639
1598 1640 if (pdtbl == NULL)
1599 1641 return (IPADM_INVALID_ARG);
1600 1642
1601 1643 for (pdp = pdtbl; pdp->ipd_name != NULL; pdp++) {
1602 1644 if (strcmp(pname, pdp->ipd_name) != 0)
1603 1645 continue;
1604 1646 if (!(pdp->ipd_proto & proto))
1605 1647 continue;
1606 1648 matched = B_TRUE;
1607 1649 /* we found a match, call the callback function */
1608 1650 if (func(arg, pdp->ipd_name, pdp->ipd_proto) == B_FALSE)
1609 1651 break;
1610 1652 }
1611 1653 if (!matched)
1612 1654 status = IPADM_PROP_UNKNOWN;
1613 1655 return (status);
1614 1656 }
1615 1657
1616 1658 /* ARGSUSED */
1617 1659 ipadm_status_t
1618 1660 i_ipadm_get_onoff(ipadm_handle_t iph, const void *arg, ipadm_prop_desc_t *dp,
1619 1661 char *buf, uint_t *bufsize, uint_t proto, uint_t valtype)
1620 1662 {
1621 1663 (void) snprintf(buf, *bufsize, "%s,%s", IPADM_ONSTR, IPADM_OFFSTR);
1622 1664 return (IPADM_SUCCESS);
1623 1665 }
1624 1666
1625 1667 /*
1626 1668 * Makes a door call to ipmgmtd to retrieve the persisted property value
1627 1669 */
1628 1670 ipadm_status_t
1629 1671 i_ipadm_get_persist_propval(ipadm_handle_t iph, ipadm_prop_desc_t *pdp,
1630 1672 char *gbuf, uint_t *gbufsize, const void *object)
1631 1673 {
1632 1674 ipmgmt_prop_arg_t parg;
1633 1675 ipmgmt_getprop_rval_t rval, *rvalp;
1634 1676 size_t nbytes;
1635 1677 int err = 0;
1636 1678
1637 1679 bzero(&parg, sizeof (parg));
1638 1680 parg.ia_cmd = IPMGMT_CMD_GETPROP;
1639 1681 i_ipadm_populate_proparg(&parg, pdp, NULL, object);
1640 1682
1641 1683 rvalp = &rval;
1642 1684 err = ipadm_door_call(iph, &parg, sizeof (parg), (void **)&rvalp,
1643 1685 sizeof (rval), B_FALSE);
1644 1686 if (err == 0) {
1645 1687 /* assert that rvalp was not reallocated */
1646 1688 assert(rvalp == &rval);
1647 1689
1648 1690 /* `ir_pval' contains the property value */
1649 1691 nbytes = snprintf(gbuf, *gbufsize, "%s", rvalp->ir_pval);
1650 1692 if (nbytes >= *gbufsize) {
1651 1693 /* insufficient buffer space */
1652 1694 *gbufsize = nbytes + 1;
1653 1695 err = ENOBUFS;
1654 1696 }
1655 1697 }
1656 1698 return (ipadm_errno2status(err));
1657 1699 }
1658 1700
1659 1701 /*
1660 1702 * Persists the property value for a given property in the data store
1661 1703 */
1662 1704 ipadm_status_t
1663 1705 i_ipadm_persist_propval(ipadm_handle_t iph, ipadm_prop_desc_t *pdp,
1664 1706 const char *pval, const void *object, uint_t flags)
1665 1707 {
1666 1708 ipmgmt_prop_arg_t parg;
1667 1709 int err = 0;
1668 1710
1669 1711 bzero(&parg, sizeof (parg));
1670 1712 i_ipadm_populate_proparg(&parg, pdp, pval, object);
1671 1713 /*
1672 1714 * Check if value to be persisted need to be appended or removed. This
1673 1715 * is required for multi-valued property.
1674 1716 */
1675 1717 if (flags & IPADM_OPT_APPEND)
1676 1718 parg.ia_flags |= IPMGMT_APPEND;
1677 1719 if (flags & IPADM_OPT_REMOVE)
1678 1720 parg.ia_flags |= IPMGMT_REMOVE;
1679 1721
1680 1722 if (flags & (IPADM_OPT_DEFAULT|IPADM_OPT_REMOVE))
1681 1723 parg.ia_cmd = IPMGMT_CMD_RESETPROP;
1682 1724 else
1683 1725 parg.ia_cmd = IPMGMT_CMD_SETPROP;
1684 1726
1685 1727 err = ipadm_door_call(iph, &parg, sizeof (parg), NULL, 0, B_FALSE);
1686 1728
1687 1729 /*
1688 1730 * its fine if there were no entry in the DB to delete. The user
1689 1731 * might be changing property value, which was not changed
1690 1732 * persistently.
1691 1733 */
1692 1734 if (err == ENOENT)
1693 1735 err = 0;
1694 1736 return (ipadm_errno2status(err));
1695 1737 }
1696 1738
1697 1739 /*
1698 1740 * This is called from ipadm_set_ifprop() to validate the set operation.
1699 1741 * It does the following steps:
1700 1742 * 1. Validates the interface name.
1701 1743 * 2. Fails if it is an IPMP meta-interface or an underlying interface.
1702 1744 * 3. In case of a persistent operation, verifies that the
1703 1745 * interface is persistent.
1704 1746 */
1705 1747 static ipadm_status_t
1706 1748 i_ipadm_validate_if(ipadm_handle_t iph, const char *ifname,
1707 1749 uint_t proto, uint_t flags)
1708 1750 {
1709 1751 sa_family_t af, other_af;
1710 1752 ipadm_status_t status;
1711 1753 boolean_t p_exists;
1712 1754 boolean_t af_exists, other_af_exists, a_exists;
1713 1755
1714 1756 /* Check if the interface name is valid. */
1715 1757 if (!i_ipadm_validate_ifname(iph, ifname))
1716 1758 return (IPADM_INVALID_ARG);
1717 1759
1718 1760 af = (proto == MOD_PROTO_IPV6 ? AF_INET6 : AF_INET);
1719 1761 /*
1720 1762 * Setting properties on an IPMP meta-interface or underlying
1721 1763 * interface is not supported.
1722 1764 */
1723 1765 if (i_ipadm_is_ipmp(iph, ifname) || i_ipadm_is_under_ipmp(iph, ifname))
1724 1766 return (IPADM_NOTSUP);
1725 1767
1726 1768 /* Check if interface exists in the persistent configuration. */
1727 1769 status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
1728 1770 if (status != IPADM_SUCCESS)
1729 1771 return (status);
1730 1772
1731 1773 /* Check if interface exists in the active configuration. */
1732 1774 af_exists = ipadm_if_enabled(iph, ifname, af);
1733 1775 other_af = (af == AF_INET ? AF_INET6 : AF_INET);
1734 1776 other_af_exists = ipadm_if_enabled(iph, ifname, other_af);
1735 1777 a_exists = (af_exists || other_af_exists);
1736 1778 if (!a_exists && p_exists)
1737 1779 return (IPADM_OP_DISABLE_OBJ);
1738 1780 if (!af_exists)
1739 1781 return (IPADM_ENXIO);
1740 1782
1741 1783 /*
1742 1784 * If a persistent operation is requested, check if the underlying
1743 1785 * IP interface is persistent.
1744 1786 */
1745 1787 if ((flags & IPADM_OPT_PERSIST) && !p_exists)
1746 1788 return (IPADM_TEMPORARY_OBJ);
1747 1789 return (IPADM_SUCCESS);
1748 1790 }
1749 1791
1750 1792 /*
1751 1793 * Private protocol properties namespace scheme:
1752 1794 *
1753 1795 * PSARC 2010/080 identified the private protocol property names to be the
1754 1796 * leading protocol names. For e.g. tcp_strong_iss, ip_strict_src_multihoming,
1755 1797 * et al,. However to be consistent with private data-link property names,
1756 1798 * which starts with '_', private protocol property names will start with '_'.
1757 1799 * For e.g. _strong_iss, _strict_src_multihoming, et al,.
1758 1800 */
1759 1801
1760 1802 /* maps new private protocol property name to the old private property name */
1761 1803 typedef struct ipadm_oname2nname_map {
1762 1804 char *iom_oname;
1763 1805 char *iom_nname;
1764 1806 uint_t iom_proto;
1765 1807 } ipadm_oname2nname_map_t;
1766 1808
1767 1809 /*
1768 1810 * IP is a special case. It isn't straight forward to derive the legacy name
1769 1811 * from the new name and vice versa. No set standard was followed in naming
1770 1812 * the properties and hence we need a table to capture the mapping.
1771 1813 */
1772 1814 static ipadm_oname2nname_map_t name_map[] = {
1773 1815 { "arp_probe_delay", "_arp_probe_delay",
1774 1816 MOD_PROTO_IP },
1775 1817 { "arp_fastprobe_delay", "_arp_fastprobe_delay",
1776 1818 MOD_PROTO_IP },
1777 1819 { "arp_probe_interval", "_arp_probe_interval",
1778 1820 MOD_PROTO_IP },
1779 1821 { "arp_fastprobe_interval", "_arp_fastprobe_interval",
1780 1822 MOD_PROTO_IP },
1781 1823 { "arp_probe_count", "_arp_probe_count",
1782 1824 MOD_PROTO_IP },
1783 1825 { "arp_fastprobe_count", "_arp_fastprobe_count",
1784 1826 MOD_PROTO_IP },
1785 1827 { "arp_defend_interval", "_arp_defend_interval",
1786 1828 MOD_PROTO_IP },
1787 1829 { "arp_defend_rate", "_arp_defend_rate",
1788 1830 MOD_PROTO_IP },
1789 1831 { "arp_defend_period", "_arp_defend_period",
1790 1832 MOD_PROTO_IP },
1791 1833 { "ndp_defend_interval", "_ndp_defend_interval",
1792 1834 MOD_PROTO_IP },
1793 1835 { "ndp_defend_rate", "_ndp_defend_rate",
1794 1836 MOD_PROTO_IP },
1795 1837 { "ndp_defend_period", "_ndp_defend_period",
1796 1838 MOD_PROTO_IP },
1797 1839 { "igmp_max_version", "_igmp_max_version",
1798 1840 MOD_PROTO_IP },
1799 1841 { "mld_max_version", "_mld_max_version",
1800 1842 MOD_PROTO_IP },
1801 1843 { "ipsec_override_persocket_policy", "_ipsec_override_persocket_policy",
1802 1844 MOD_PROTO_IP },
1803 1845 { "ipsec_policy_log_interval", "_ipsec_policy_log_interval",
1804 1846 MOD_PROTO_IP },
1805 1847 { "icmp_accept_clear_messages", "_icmp_accept_clear_messages",
1806 1848 MOD_PROTO_IP },
1807 1849 { "igmp_accept_clear_messages", "_igmp_accept_clear_messages",
1808 1850 MOD_PROTO_IP },
1809 1851 { "pim_accept_clear_messages", "_pim_accept_clear_messages",
1810 1852 MOD_PROTO_IP },
1811 1853 { "ip_respond_to_echo_multicast", "_respond_to_echo_multicast",
1812 1854 MOD_PROTO_IPV4 },
1813 1855 { "ip_send_redirects", "_send_redirects",
1814 1856 MOD_PROTO_IPV4 },
1815 1857 { "ip_forward_src_routed", "_forward_src_routed",
1816 1858 MOD_PROTO_IPV4 },
1817 1859 { "ip_icmp_return_data_bytes", "_icmp_return_data_bytes",
1818 1860 MOD_PROTO_IPV4 },
1819 1861 { "ip_ignore_redirect", "_ignore_redirect",
1820 1862 MOD_PROTO_IPV4 },
1821 1863 { "ip_strict_dst_multihoming", "_strict_dst_multihoming",
1822 1864 MOD_PROTO_IPV4 },
1823 1865 { "ip_reasm_timeout", "_reasm_timeout",
1824 1866 MOD_PROTO_IPV4 },
1825 1867 { "ip_strict_src_multihoming", "_strict_src_multihoming",
1826 1868 MOD_PROTO_IPV4 },
1827 1869 { "ipv4_dad_announce_interval", "_dad_announce_interval",
1828 1870 MOD_PROTO_IPV4 },
1829 1871 { "ipv4_icmp_return_pmtu", "_icmp_return_pmtu",
1830 1872 MOD_PROTO_IPV4 },
1831 1873 { "ipv6_dad_announce_interval", "_dad_announce_interval",
1832 1874 MOD_PROTO_IPV6 },
1833 1875 { "ipv6_icmp_return_pmtu", "_icmp_return_pmtu",
1834 1876 MOD_PROTO_IPV6 },
1835 1877 { NULL, NULL, MOD_PROTO_NONE }
1836 1878 };
1837 1879
1838 1880 /*
1839 1881 * Following API returns a new property name in `nname' for the given legacy
1840 1882 * property name in `oname'.
1841 1883 */
1842 1884 int
1843 1885 ipadm_legacy2new_propname(const char *oname, char *nname, uint_t nnamelen,
1844 1886 uint_t *proto)
1845 1887 {
1846 1888 const char *str;
1847 1889 ipadm_oname2nname_map_t *ionmp;
1848 1890
1849 1891 /* if it's a public property, there is nothing to return */
1850 1892 if (i_ipadm_get_prop_desc(oname, *proto, NULL) != NULL)
1851 1893 return (-1);
1852 1894
1853 1895 /*
1854 1896 * we didn't find the `oname' in the table, check if the property
1855 1897 * name begins with a leading protocol.
1856 1898 */
1857 1899 str = oname;
1858 1900 switch (*proto) {
1859 1901 case MOD_PROTO_TCP:
1860 1902 if (strstr(oname, "tcp_") == oname)
1861 1903 str += strlen("tcp");
1862 1904 break;
1863 1905 case MOD_PROTO_SCTP:
1864 1906 if (strstr(oname, "sctp_") == oname)
1865 1907 str += strlen("sctp");
1866 1908 break;
1867 1909 case MOD_PROTO_UDP:
1868 1910 if (strstr(oname, "udp_") == oname)
1869 1911 str += strlen("udp");
1870 1912 break;
1871 1913 case MOD_PROTO_RAWIP:
1872 1914 if (strstr(oname, "icmp_") == oname)
1873 1915 str += strlen("icmp");
1874 1916 break;
1875 1917 case MOD_PROTO_IP:
1876 1918 case MOD_PROTO_IPV4:
1877 1919 case MOD_PROTO_IPV6:
1878 1920 if (strstr(oname, "ip6_") == oname) {
1879 1921 *proto = MOD_PROTO_IPV6;
1880 1922 str += strlen("ip6");
1881 1923 } else {
1882 1924 for (ionmp = name_map; ionmp->iom_oname != NULL;
1883 1925 ionmp++) {
1884 1926 if (strcmp(oname, ionmp->iom_oname) == 0) {
1885 1927 str = ionmp->iom_nname;
1886 1928 *proto = ionmp->iom_proto;
1887 1929 break;
1888 1930 }
1889 1931 }
1890 1932 if (ionmp->iom_oname != NULL)
1891 1933 break;
1892 1934
1893 1935 if (strstr(oname, "ip_") == oname) {
1894 1936 *proto = MOD_PROTO_IP;
1895 1937 str += strlen("ip");
1896 1938 }
1897 1939 }
1898 1940 break;
1899 1941 default:
1900 1942 return (-1);
1901 1943 }
1902 1944 (void) snprintf(nname, nnamelen, "%s", str);
1903 1945 return (0);
1904 1946 }
1905 1947
1906 1948 /*
1907 1949 * Following API is required for ndd.c alone. To maintain backward
1908 1950 * compatibility with ndd output, we need to print the legacy name
1909 1951 * for the new name.
1910 1952 */
1911 1953 int
1912 1954 ipadm_new2legacy_propname(const char *oname, char *nname,
1913 1955 uint_t nnamelen, uint_t proto)
1914 1956 {
1915 1957 char *prefix;
1916 1958 ipadm_oname2nname_map_t *ionmp;
1917 1959
1918 1960 /* if it's a public property, there is nothing to prepend */
1919 1961 if (i_ipadm_get_prop_desc(oname, proto, NULL) != NULL)
1920 1962 return (-1);
1921 1963
1922 1964 switch (proto) {
1923 1965 case MOD_PROTO_TCP:
1924 1966 prefix = "tcp";
1925 1967 break;
1926 1968 case MOD_PROTO_SCTP:
1927 1969 prefix = "sctp";
1928 1970 break;
1929 1971 case MOD_PROTO_UDP:
1930 1972 prefix = "udp";
1931 1973 break;
1932 1974 case MOD_PROTO_RAWIP:
1933 1975 prefix = "icmp";
1934 1976 break;
1935 1977 case MOD_PROTO_IP:
1936 1978 case MOD_PROTO_IPV4:
1937 1979 case MOD_PROTO_IPV6:
1938 1980 /* handle special case for IP */
1939 1981 for (ionmp = name_map; ionmp->iom_oname != NULL; ionmp++) {
1940 1982 if (strcmp(oname, ionmp->iom_nname) == 0 &&
1941 1983 ionmp->iom_proto == proto) {
1942 1984 (void) strlcpy(nname, ionmp->iom_oname,
1943 1985 nnamelen);
1944 1986 return (0);
1945 1987 }
1946 1988 }
1947 1989 if (proto == MOD_PROTO_IPV6)
1948 1990 prefix = "ip6";
1949 1991 else
1950 1992 prefix = "ip";
1951 1993 break;
1952 1994 default:
1953 1995 return (-1);
1954 1996 }
1955 1997 (void) snprintf(nname, nnamelen, "%s%s", prefix, oname);
1956 1998 return (0);
1957 1999 }
|
↓ open down ↓ |
1133 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX