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