4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2013 by Delphix. All rights reserved.
27 * This file contains routines that are used to modify/retrieve protocol or
28 * interface property values. It also holds all the supported properties for
29 * both IP interface and protocols in `ipadm_prop_desc_t'. Following protocols
30 * are supported: IP, IPv4, IPv6, TCP, SCTP, UDP and ICMP.
32 * This file also contains walkers, which walks through the property table and
33 * calls the callback function, of the form `ipadm_prop_wfunc_t' , for every
34 * property in the table.
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45 #include <sys/sockio.h>
47 #include <libdllink.h>
49 #include "libipadm_impl.h"
50 #include <inet/tunables.h>
52 #define IPADM_NONESTR "none"
53 #define DEF_METRIC_VAL 0 /* default metric value */
55 #define A_CNT(arr) (sizeof (arr) / sizeof (arr[0]))
57 static ipadm_status_t
i_ipadm_validate_if(ipadm_handle_t
, const char *,
61 * Callback functions to retrieve property values from the kernel. These
62 * functions, when required, translate the values from the kernel to a format
63 * suitable for printing. For example: boolean values will be translated
64 * to on/off. They also retrieve DEFAULT, PERM and POSSIBLE values for
67 static ipadm_pd_getf_t i_ipadm_get_prop
, i_ipadm_get_ifprop_flags
,
68 i_ipadm_get_mtu
, i_ipadm_get_metric
,
69 i_ipadm_get_usesrc
, i_ipadm_get_forwarding
,
70 i_ipadm_get_ecnsack
, i_ipadm_get_hostmodel
;
73 * Callback function to set property values. These functions translate the
74 * values to a format suitable for kernel consumption, allocates the necessary
75 * ioctl buffers and then invokes ioctl().
77 static ipadm_pd_setf_t i_ipadm_set_prop
, i_ipadm_set_mtu
,
78 i_ipadm_set_ifprop_flags
,
79 i_ipadm_set_metric
, i_ipadm_set_usesrc
,
80 i_ipadm_set_forwarding
, i_ipadm_set_eprivport
,
81 i_ipadm_set_ecnsack
, i_ipadm_set_hostmodel
;
83 /* array of protocols we support */
84 static int protocols
[] = { MOD_PROTO_IP
, MOD_PROTO_RAWIP
,
85 MOD_PROTO_TCP
, MOD_PROTO_UDP
,
89 * Supported IP protocol properties.
91 static ipadm_prop_desc_t ipadm_ip_prop_table
[] = {
92 { "arp", NULL
, IPADMPROP_CLASS_IF
, MOD_PROTO_IPV4
, 0,
93 i_ipadm_set_ifprop_flags
, i_ipadm_get_onoff
,
94 i_ipadm_get_ifprop_flags
},
96 { "forwarding", NULL
, IPADMPROP_CLASS_MODIF
, MOD_PROTO_IPV4
, 0,
97 i_ipadm_set_forwarding
, i_ipadm_get_onoff
,
98 i_ipadm_get_forwarding
},
100 { "metric", NULL
, IPADMPROP_CLASS_IF
, MOD_PROTO_IPV4
, 0,
101 i_ipadm_set_metric
, NULL
, i_ipadm_get_metric
},
103 { "mtu", NULL
, IPADMPROP_CLASS_IF
, MOD_PROTO_IPV4
, 0,
104 i_ipadm_set_mtu
, i_ipadm_get_mtu
, i_ipadm_get_mtu
},
106 { "exchange_routes", NULL
, IPADMPROP_CLASS_IF
, MOD_PROTO_IPV4
, 0,
107 i_ipadm_set_ifprop_flags
, i_ipadm_get_onoff
,
108 i_ipadm_get_ifprop_flags
},
110 { "usesrc", NULL
, IPADMPROP_CLASS_IF
, MOD_PROTO_IPV4
, 0,
111 i_ipadm_set_usesrc
, NULL
, i_ipadm_get_usesrc
},
113 { "ttl", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_IPV4
, 0,
114 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
116 { "forwarding", NULL
, IPADMPROP_CLASS_MODIF
, MOD_PROTO_IPV6
, 0,
117 i_ipadm_set_forwarding
, i_ipadm_get_onoff
,
118 i_ipadm_get_forwarding
},
120 { "hoplimit", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_IPV6
, 0,
121 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
123 { "metric", NULL
, IPADMPROP_CLASS_IF
, MOD_PROTO_IPV6
, 0,
124 i_ipadm_set_metric
, NULL
, i_ipadm_get_metric
},
126 { "mtu", NULL
, IPADMPROP_CLASS_IF
, MOD_PROTO_IPV6
, 0,
127 i_ipadm_set_mtu
, i_ipadm_get_mtu
, i_ipadm_get_mtu
},
129 { "nud", NULL
, IPADMPROP_CLASS_IF
, MOD_PROTO_IPV6
, 0,
130 i_ipadm_set_ifprop_flags
, i_ipadm_get_onoff
,
131 i_ipadm_get_ifprop_flags
},
133 { "exchange_routes", NULL
, IPADMPROP_CLASS_IF
, MOD_PROTO_IPV6
, 0,
134 i_ipadm_set_ifprop_flags
, i_ipadm_get_onoff
,
135 i_ipadm_get_ifprop_flags
},
137 { "usesrc", NULL
, IPADMPROP_CLASS_IF
, MOD_PROTO_IPV6
, 0,
138 i_ipadm_set_usesrc
, NULL
, i_ipadm_get_usesrc
},
140 { "hostmodel", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_IPV6
, 0,
141 i_ipadm_set_hostmodel
, i_ipadm_get_hostmodel
,
142 i_ipadm_get_hostmodel
},
144 { "hostmodel", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_IPV4
, 0,
145 i_ipadm_set_hostmodel
, i_ipadm_get_hostmodel
,
146 i_ipadm_get_hostmodel
},
148 { NULL
, NULL
, 0, 0, 0, NULL
, NULL
, NULL
}
151 /* possible values for TCP properties `ecn' and `sack' */
152 static const char *ecn_sack_vals
[] = {"never", "passive", "active", NULL
};
154 /* Supported TCP protocol properties */
155 static ipadm_prop_desc_t ipadm_tcp_prop_table
[] = {
156 { "ecn", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_TCP
, 0,
157 i_ipadm_set_ecnsack
, i_ipadm_get_ecnsack
, i_ipadm_get_ecnsack
},
159 { "extra_priv_ports", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_TCP
,
160 IPADMPROP_MULVAL
, i_ipadm_set_eprivport
, i_ipadm_get_prop
,
163 { "largest_anon_port", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_TCP
, 0,
164 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
166 { "max_buf", "_max_buf", IPADMPROP_CLASS_MODULE
, MOD_PROTO_TCP
, 0,
167 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
169 { "recv_buf", "recv_maxbuf", IPADMPROP_CLASS_MODULE
, MOD_PROTO_TCP
, 0,
170 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
172 { "sack", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_TCP
, 0,
173 i_ipadm_set_ecnsack
, i_ipadm_get_ecnsack
, i_ipadm_get_ecnsack
},
175 { "send_buf", "send_maxbuf", IPADMPROP_CLASS_MODULE
, MOD_PROTO_TCP
, 0,
176 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
178 { "smallest_anon_port", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_TCP
, 0,
179 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
181 { "smallest_nonpriv_port", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_TCP
,
182 0, i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
184 { NULL
, NULL
, 0, 0, 0, NULL
, NULL
, NULL
}
187 /* Supported UDP protocol properties */
188 static ipadm_prop_desc_t ipadm_udp_prop_table
[] = {
189 { "extra_priv_ports", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_UDP
,
190 IPADMPROP_MULVAL
, i_ipadm_set_eprivport
, i_ipadm_get_prop
,
193 { "largest_anon_port", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_UDP
, 0,
194 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
196 { "max_buf", "_max_buf", IPADMPROP_CLASS_MODULE
, MOD_PROTO_UDP
, 0,
197 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
199 { "recv_buf", "recv_maxbuf", IPADMPROP_CLASS_MODULE
, MOD_PROTO_UDP
, 0,
200 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
202 { "send_buf", "send_maxbuf", IPADMPROP_CLASS_MODULE
, MOD_PROTO_UDP
, 0,
203 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
205 { "smallest_anon_port", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_UDP
, 0,
206 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
208 { "smallest_nonpriv_port", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_UDP
,
209 0, i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
211 { NULL
, NULL
, 0, 0, 0, NULL
, NULL
, NULL
}
214 /* Supported SCTP protocol properties */
215 static ipadm_prop_desc_t ipadm_sctp_prop_table
[] = {
216 { "extra_priv_ports", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_SCTP
,
217 IPADMPROP_MULVAL
, i_ipadm_set_eprivport
, i_ipadm_get_prop
,
220 { "largest_anon_port", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_SCTP
, 0,
221 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
223 { "max_buf", "_max_buf", IPADMPROP_CLASS_MODULE
, MOD_PROTO_SCTP
, 0,
224 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
226 { "recv_buf", "recv_maxbuf", IPADMPROP_CLASS_MODULE
, MOD_PROTO_SCTP
, 0,
227 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
229 { "send_buf", "send_maxbuf", IPADMPROP_CLASS_MODULE
, MOD_PROTO_SCTP
, 0,
230 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
232 { "smallest_anon_port", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_SCTP
, 0,
233 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
235 { "smallest_nonpriv_port", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_SCTP
,
236 0, i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
238 { NULL
, NULL
, 0, 0, 0, NULL
, NULL
, NULL
}
241 /* Supported ICMP protocol properties */
242 static ipadm_prop_desc_t ipadm_icmp_prop_table
[] = {
243 { "max_buf", "_max_buf", IPADMPROP_CLASS_MODULE
, MOD_PROTO_RAWIP
, 0,
244 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
246 { "recv_buf", "recv_maxbuf", IPADMPROP_CLASS_MODULE
, MOD_PROTO_RAWIP
, 0,
247 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
249 { "send_buf", "send_maxbuf", IPADMPROP_CLASS_MODULE
, MOD_PROTO_RAWIP
, 0,
250 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
252 { NULL
, NULL
, 0, 0, 0, NULL
, NULL
, NULL
}
256 * A dummy private property structure, used while handling private
257 * protocol properties (properties not yet supported by libipadm).
259 static ipadm_prop_desc_t ipadm_privprop
=
260 { NULL
, NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_NONE
, 0,
261 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
};
264 * Returns the property description table, for the given protocol
266 static ipadm_prop_desc_t
*
267 i_ipadm_get_propdesc_table(uint_t proto
)
273 return (ipadm_ip_prop_table
);
274 case MOD_PROTO_RAWIP
:
275 return (ipadm_icmp_prop_table
);
277 return (ipadm_tcp_prop_table
);
279 return (ipadm_udp_prop_table
);
281 return (ipadm_sctp_prop_table
);
287 static ipadm_prop_desc_t
*
288 i_ipadm_get_prop_desc(const char *pname
, uint_t proto
, int *errp
)
291 boolean_t matched_name
= B_FALSE
;
292 ipadm_prop_desc_t
*ipdp
= NULL
, *ipdtbl
;
294 if ((ipdtbl
= i_ipadm_get_propdesc_table(proto
)) == NULL
) {
299 for (ipdp
= ipdtbl
; ipdp
->ipd_name
!= NULL
; ipdp
++) {
300 if (strcmp(pname
, ipdp
->ipd_name
) == 0 ||
301 (ipdp
->ipd_old_name
!= NULL
&&
302 strcmp(pname
, ipdp
->ipd_old_name
) == 0)) {
303 matched_name
= B_TRUE
;
304 if (ipdp
->ipd_proto
== proto
)
309 if (ipdp
->ipd_name
== NULL
) {
311 /* if we matched name, but failed protocol check */
323 ipadm_proto2str(uint_t proto
)
332 case MOD_PROTO_RAWIP
:
346 ipadm_str2proto(const char *protostr
)
348 if (protostr
== NULL
)
349 return (MOD_PROTO_NONE
);
350 if (strcmp(protostr
, "tcp") == 0)
351 return (MOD_PROTO_TCP
);
352 else if (strcmp(protostr
, "udp") == 0)
353 return (MOD_PROTO_UDP
);
354 else if (strcmp(protostr
, "ip") == 0)
355 return (MOD_PROTO_IP
);
356 else if (strcmp(protostr
, "ipv4") == 0)
357 return (MOD_PROTO_IPV4
);
358 else if (strcmp(protostr
, "ipv6") == 0)
359 return (MOD_PROTO_IPV6
);
360 else if (strcmp(protostr
, "icmp") == 0)
361 return (MOD_PROTO_RAWIP
);
362 else if (strcmp(protostr
, "sctp") == 0)
363 return (MOD_PROTO_SCTP
);
364 else if (strcmp(protostr
, "arp") == 0)
365 return (MOD_PROTO_IP
);
367 return (MOD_PROTO_NONE
);
371 static ipadm_status_t
372 i_ipadm_set_mtu(ipadm_handle_t iph
, const void *arg
,
373 ipadm_prop_desc_t
*pdp
, const void *pval
, uint_t proto
, uint_t flags
)
379 const char *ifname
= arg
;
380 char val
[MAXPROPVALLEN
];
382 /* to reset MTU first retrieve the default MTU and then set it */
383 if (flags
& IPADM_OPT_DEFAULT
) {
384 ipadm_status_t status
;
385 uint_t size
= MAXPROPVALLEN
;
387 status
= i_ipadm_get_prop(iph
, arg
, pdp
, val
, &size
,
388 proto
, MOD_PROP_DEFAULT
);
389 if (status
!= IPADM_SUCCESS
)
395 mtu
= (uint_t
)strtol(pval
, &endp
, 10);
396 if (errno
!= 0 || *endp
!= '\0')
397 return (IPADM_INVALID_ARG
);
399 bzero(&lifr
, sizeof (lifr
));
400 (void) strlcpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
403 s
= (proto
== MOD_PROTO_IPV6
? iph
->iph_sock6
: iph
->iph_sock
);
404 if (ioctl(s
, SIOCSLIFMTU
, (caddr_t
)&lifr
) < 0)
405 return (ipadm_errno2status(errno
));
407 return (IPADM_SUCCESS
);
411 static ipadm_status_t
412 i_ipadm_set_metric(ipadm_handle_t iph
, const void *arg
,
413 ipadm_prop_desc_t
*pdp
, const void *pval
, uint_t proto
, uint_t flags
)
418 const char *ifname
= arg
;
421 /* if we are resetting, set the value to its default value */
422 if (flags
& IPADM_OPT_DEFAULT
) {
423 metric
= DEF_METRIC_VAL
;
426 metric
= (uint_t
)strtol(pval
, &endp
, 10);
427 if (errno
!= 0 || *endp
!= '\0')
428 return (IPADM_INVALID_ARG
);
431 bzero(&lifr
, sizeof (lifr
));
432 (void) strlcpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
433 lifr
.lifr_metric
= metric
;
435 s
= (proto
== MOD_PROTO_IPV6
? iph
->iph_sock6
: iph
->iph_sock
);
437 if (ioctl(s
, SIOCSLIFMETRIC
, (caddr_t
)&lifr
) < 0)
438 return (ipadm_errno2status(errno
));
440 return (IPADM_SUCCESS
);
444 static ipadm_status_t
445 i_ipadm_set_usesrc(ipadm_handle_t iph
, const void *arg
,
446 ipadm_prop_desc_t
*pdp
, const void *pval
, uint_t proto
, uint_t flags
)
449 const char *ifname
= arg
;
453 /* if we are resetting, set the value to its default value */
454 if (flags
& IPADM_OPT_DEFAULT
)
455 pval
= IPADM_NONESTR
;
458 * cannot specify logical interface name. We can also filter out other
459 * bogus interface names here itself through i_ipadm_validate_ifname().
461 if (strcmp(pval
, IPADM_NONESTR
) != 0 &&
462 !i_ipadm_validate_ifname(iph
, pval
))
463 return (IPADM_INVALID_ARG
);
465 bzero(&lifr
, sizeof (lifr
));
466 (void) strlcpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
468 s
= (proto
== MOD_PROTO_IPV6
? iph
->iph_sock6
: iph
->iph_sock
);
470 if (strcmp(pval
, IPADM_NONESTR
) != 0) {
471 if ((ifindex
= if_nametoindex(pval
)) == 0)
472 return (ipadm_errno2status(errno
));
473 lifr
.lifr_index
= ifindex
;
475 if (ioctl(s
, SIOCGLIFUSESRC
, (caddr_t
)&lifr
) < 0)
476 return (ipadm_errno2status(errno
));
479 if (ioctl(s
, SIOCSLIFUSESRC
, (caddr_t
)&lifr
) < 0)
480 return (ipadm_errno2status(errno
));
482 return (IPADM_SUCCESS
);
485 static struct hostmodel_strval
{
487 ip_hostmodel_t esm_val
;
489 {"weak", IP_WEAK_ES
},
490 {"src-priority", IP_SRC_PRI_ES
},
491 {"strong", IP_STRONG_ES
},
492 {"custom", IP_MAXVAL_ES
}
495 static ip_hostmodel_t
496 i_ipadm_hostmodel_str2val(const char *pval
)
500 for (i
= 0; i
< A_CNT(esm_arr
); i
++) {
501 if (esm_arr
[i
].esm_str
!= NULL
&&
502 strcmp(pval
, esm_arr
[i
].esm_str
) == 0) {
503 return (esm_arr
[i
].esm_val
);
506 return (IP_MAXVAL_ES
);
510 i_ipadm_hostmodel_val2str(ip_hostmodel_t pval
)
514 for (i
= 0; i
< A_CNT(esm_arr
); i
++) {
515 if (esm_arr
[i
].esm_val
== pval
)
516 return (esm_arr
[i
].esm_str
);
522 static ipadm_status_t
523 i_ipadm_set_hostmodel(ipadm_handle_t iph
, const void *arg
,
524 ipadm_prop_desc_t
*pdp
, const void *pval
, uint_t proto
, uint_t flags
)
526 ip_hostmodel_t hostmodel
;
527 char val
[11]; /* covers uint32_max as a string */
529 if ((flags
& IPADM_OPT_DEFAULT
) == 0) {
530 hostmodel
= i_ipadm_hostmodel_str2val(pval
);
531 if (hostmodel
== IP_MAXVAL_ES
)
532 return (IPADM_INVALID_ARG
);
533 (void) snprintf(val
, sizeof (val
), "%d", hostmodel
);
536 return (i_ipadm_set_prop(iph
, NULL
, pdp
, pval
, proto
, flags
));
540 static ipadm_status_t
541 i_ipadm_get_hostmodel(ipadm_handle_t iph
, const void *arg
,
542 ipadm_prop_desc_t
*pdp
, char *buf
, uint_t
*bufsize
, uint_t proto
,
545 ip_hostmodel_t hostmodel
;
548 ipadm_status_t status
;
552 nbytes
= snprintf(buf
, *bufsize
, "%d", MOD_PROP_PERM_RW
);
554 case MOD_PROP_DEFAULT
:
555 nbytes
= snprintf(buf
, *bufsize
, "weak");
557 case MOD_PROP_ACTIVE
:
558 status
= i_ipadm_get_prop(iph
, arg
, pdp
, buf
, bufsize
, proto
,
560 if (status
!= IPADM_SUCCESS
)
562 bcopy(buf
, &hostmodel
, sizeof (hostmodel
));
563 cp
= i_ipadm_hostmodel_val2str(hostmodel
);
564 nbytes
= snprintf(buf
, *bufsize
, "%s",
565 (cp
!= NULL
? cp
: "?"));
567 case MOD_PROP_POSSIBLE
:
568 nbytes
= snprintf(buf
, *bufsize
, "strong,src-priority,weak");
571 return (IPADM_INVALID_ARG
);
573 if (nbytes
>= *bufsize
) {
574 /* insufficient buffer space */
575 *bufsize
= nbytes
+ 1;
576 return (IPADM_NO_BUFS
);
578 return (IPADM_SUCCESS
);
582 static ipadm_status_t
583 i_ipadm_set_ifprop_flags(ipadm_handle_t iph
, const void *arg
,
584 ipadm_prop_desc_t
*pdp
, const void *pval
, uint_t proto
, uint_t flags
)
586 ipadm_status_t status
= IPADM_SUCCESS
;
587 const char *ifname
= arg
;
588 uint64_t on_flags
= 0, off_flags
= 0;
589 boolean_t on
= B_FALSE
;
590 sa_family_t af
= (proto
== MOD_PROTO_IPV6
? AF_INET6
: AF_INET
);
592 /* if we are resetting, set the value to its default value */
593 if (flags
& IPADM_OPT_DEFAULT
) {
594 if (strcmp(pdp
->ipd_name
, "exchange_routes") == 0 ||
595 strcmp(pdp
->ipd_name
, "arp") == 0 ||
596 strcmp(pdp
->ipd_name
, "nud") == 0) {
598 } else if (strcmp(pdp
->ipd_name
, "forwarding") == 0) {
601 return (IPADM_PROP_UNKNOWN
);
605 if (strcmp(pval
, IPADM_ONSTR
) == 0)
607 else if (strcmp(pval
, IPADM_OFFSTR
) == 0)
610 return (IPADM_INVALID_ARG
);
612 if (strcmp(pdp
->ipd_name
, "exchange_routes") == 0) {
614 off_flags
= IFF_NORTEXCH
;
616 on_flags
= IFF_NORTEXCH
;
617 } else if (strcmp(pdp
->ipd_name
, "arp") == 0) {
619 off_flags
= IFF_NOARP
;
621 on_flags
= IFF_NOARP
;
622 } else if (strcmp(pdp
->ipd_name
, "nud") == 0) {
624 off_flags
= IFF_NONUD
;
626 on_flags
= IFF_NONUD
;
627 } else if (strcmp(pdp
->ipd_name
, "forwarding") == 0) {
629 on_flags
= IFF_ROUTER
;
631 off_flags
= IFF_ROUTER
;
634 if (on_flags
|| off_flags
) {
635 status
= i_ipadm_set_flags(iph
, ifname
, af
, on_flags
,
642 static ipadm_status_t
643 i_ipadm_set_eprivport(ipadm_handle_t iph
, const void *arg
,
644 ipadm_prop_desc_t
*pdp
, const void *pval
, uint_t proto
, uint_t flags
)
646 nvlist_t
*portsnvl
= NULL
;
648 ipadm_status_t status
= IPADM_SUCCESS
;
652 if (flags
& IPADM_OPT_DEFAULT
) {
653 assert(pval
== NULL
);
654 return (i_ipadm_set_prop(iph
, arg
, pdp
, pval
, proto
, flags
));
657 if ((err
= ipadm_str2nvlist(pval
, &portsnvl
, IPADM_NORVAL
)) != 0)
658 return (ipadm_errno2status(err
));
660 /* count the number of ports */
661 for (nvp
= nvlist_next_nvpair(portsnvl
, NULL
); nvp
!= NULL
;
662 nvp
= nvlist_next_nvpair(portsnvl
, nvp
)) {
666 if (iph
->iph_flags
& IPH_INIT
) {
667 flags
|= IPADM_OPT_APPEND
;
668 } else if (count
> 1) {
670 * We allow only one port to be added, removed or
671 * assigned at a time.
673 * However on reboot, while initializing protocol
674 * properties, extra_priv_ports might have multiple
675 * values. Only in that case we allow setting multiple
678 nvlist_free(portsnvl
);
679 return (IPADM_INVALID_ARG
);
682 for (nvp
= nvlist_next_nvpair(portsnvl
, NULL
); nvp
!= NULL
;
683 nvp
= nvlist_next_nvpair(portsnvl
, nvp
)) {
684 status
= i_ipadm_set_prop(iph
, arg
, pdp
, nvpair_name(nvp
),
686 if (status
!= IPADM_SUCCESS
)
689 nvlist_free(portsnvl
);
694 static ipadm_status_t
695 i_ipadm_set_forwarding(ipadm_handle_t iph
, const void *arg
,
696 ipadm_prop_desc_t
*pdp
, const void *pval
, uint_t proto
, uint_t flags
)
698 const char *ifname
= arg
;
699 ipadm_status_t status
;
702 * if interface name is provided, then set forwarding using the
705 if (ifname
!= NULL
) {
706 status
= i_ipadm_set_ifprop_flags(iph
, ifname
, pdp
, pval
,
712 * if the caller is IPH_LEGACY, `pval' already contains
715 if (!(flags
& IPADM_OPT_DEFAULT
) &&
716 !(iph
->iph_flags
& IPH_LEGACY
)) {
718 if (strcmp(pval
, IPADM_ONSTR
) == 0)
720 else if (strcmp(pval
, IPADM_OFFSTR
) == 0)
723 return (IPADM_INVALID_ARG
);
727 status
= i_ipadm_set_prop(iph
, ifname
, pdp
, pval
, proto
, flags
);
734 static ipadm_status_t
735 i_ipadm_set_ecnsack(ipadm_handle_t iph
, const void *arg
,
736 ipadm_prop_desc_t
*pdp
, const void *pval
, uint_t proto
, uint_t flags
)
739 char val
[MAXPROPVALLEN
];
741 /* if IPH_LEGACY is set, `pval' already contains numeric values */
742 if (!(flags
& IPADM_OPT_DEFAULT
) && !(iph
->iph_flags
& IPH_LEGACY
)) {
743 for (i
= 0; ecn_sack_vals
[i
] != NULL
; i
++) {
744 if (strcmp(pval
, ecn_sack_vals
[i
]) == 0)
747 if (ecn_sack_vals
[i
] == NULL
)
748 return (IPADM_INVALID_ARG
);
749 (void) snprintf(val
, MAXPROPVALLEN
, "%d", i
);
753 return (i_ipadm_set_prop(iph
, arg
, pdp
, pval
, proto
, flags
));
758 i_ipadm_get_ecnsack(ipadm_handle_t iph
, const void *arg
,
759 ipadm_prop_desc_t
*pdp
, char *buf
, uint_t
*bufsize
, uint_t proto
,
762 ipadm_status_t status
= IPADM_SUCCESS
;
763 uint_t i
, nbytes
= 0;
766 case MOD_PROP_POSSIBLE
:
767 for (i
= 0; ecn_sack_vals
[i
] != NULL
; i
++) {
769 nbytes
+= snprintf(buf
+ nbytes
,
770 *bufsize
- nbytes
, "%s", ecn_sack_vals
[i
]);
772 nbytes
+= snprintf(buf
+ nbytes
,
773 *bufsize
- nbytes
, ",%s", ecn_sack_vals
[i
]);
774 if (nbytes
>= *bufsize
)
779 case MOD_PROP_DEFAULT
:
780 case MOD_PROP_ACTIVE
:
781 status
= i_ipadm_get_prop(iph
, arg
, pdp
, buf
, bufsize
, proto
,
785 * If IPH_LEGACY is set, do not convert the value returned
788 if (iph
->iph_flags
& IPH_LEGACY
)
792 * For current and default value, convert the value returned
793 * from kernel to more discrete representation.
795 if (status
== IPADM_SUCCESS
&& (valtype
== MOD_PROP_ACTIVE
||
796 valtype
== MOD_PROP_DEFAULT
)) {
799 nbytes
= snprintf(buf
, *bufsize
, "%s",
804 return (IPADM_INVALID_ARG
);
806 if (nbytes
>= *bufsize
) {
807 /* insufficient buffer space */
808 *bufsize
= nbytes
+ 1;
809 return (IPADM_NO_BUFS
);
816 static ipadm_status_t
817 i_ipadm_get_forwarding(ipadm_handle_t iph
, const void *arg
,
818 ipadm_prop_desc_t
*pdp
, char *buf
, uint_t
*bufsize
, uint_t proto
,
821 const char *ifname
= arg
;
822 ipadm_status_t status
= IPADM_SUCCESS
;
825 * if interface name is provided, then get forwarding status using
828 if (ifname
!= NULL
) {
829 status
= i_ipadm_get_ifprop_flags(iph
, ifname
, pdp
,
830 buf
, bufsize
, pdp
->ipd_proto
, valtype
);
832 status
= i_ipadm_get_prop(iph
, ifname
, pdp
, buf
,
833 bufsize
, proto
, valtype
);
835 * If IPH_LEGACY is set, do not convert the value returned
838 if (iph
->iph_flags
& IPH_LEGACY
)
840 if (status
== IPADM_SUCCESS
&& (valtype
== MOD_PROP_ACTIVE
||
841 valtype
== MOD_PROP_DEFAULT
)) {
842 uint_t val
= atoi(buf
);
844 (void) snprintf(buf
, *bufsize
,
845 (val
== 1 ? IPADM_ONSTR
: IPADM_OFFSTR
));
854 static ipadm_status_t
855 i_ipadm_get_mtu(ipadm_handle_t iph
, const void *arg
,
856 ipadm_prop_desc_t
*pdp
, char *buf
, uint_t
*bufsize
, uint_t proto
,
860 const char *ifname
= arg
;
866 nbytes
= snprintf(buf
, *bufsize
, "%d", MOD_PROP_PERM_RW
);
868 case MOD_PROP_DEFAULT
:
869 case MOD_PROP_POSSIBLE
:
870 return (i_ipadm_get_prop(iph
, arg
, pdp
, buf
, bufsize
,
872 case MOD_PROP_ACTIVE
:
873 bzero(&lifr
, sizeof (lifr
));
874 (void) strlcpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
875 s
= (proto
== MOD_PROTO_IPV6
? iph
->iph_sock6
: iph
->iph_sock
);
877 if (ioctl(s
, SIOCGLIFMTU
, (caddr_t
)&lifr
) < 0)
878 return (ipadm_errno2status(errno
));
879 nbytes
= snprintf(buf
, *bufsize
, "%u", lifr
.lifr_mtu
);
882 return (IPADM_INVALID_ARG
);
884 if (nbytes
>= *bufsize
) {
885 /* insufficient buffer space */
886 *bufsize
= nbytes
+ 1;
887 return (IPADM_NO_BUFS
);
889 return (IPADM_SUCCESS
);
893 static ipadm_status_t
894 i_ipadm_get_metric(ipadm_handle_t iph
, const void *arg
,
895 ipadm_prop_desc_t
*pdp
, char *buf
, uint_t
*bufsize
, uint_t proto
,
899 const char *ifname
= arg
;
905 val
= MOD_PROP_PERM_RW
;
907 case MOD_PROP_DEFAULT
:
908 val
= DEF_METRIC_VAL
;
910 case MOD_PROP_ACTIVE
:
911 bzero(&lifr
, sizeof (lifr
));
912 (void) strlcpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
914 s
= (proto
== MOD_PROTO_IPV6
? iph
->iph_sock6
: iph
->iph_sock
);
915 if (ioctl(s
, SIOCGLIFMETRIC
, (caddr_t
)&lifr
) < 0)
916 return (ipadm_errno2status(errno
));
917 val
= lifr
.lifr_metric
;
920 return (IPADM_INVALID_ARG
);
922 nbytes
= snprintf(buf
, *bufsize
, "%d", val
);
923 if (nbytes
>= *bufsize
) {
924 /* insufficient buffer space */
925 *bufsize
= nbytes
+ 1;
926 return (IPADM_NO_BUFS
);
929 return (IPADM_SUCCESS
);
933 static ipadm_status_t
934 i_ipadm_get_usesrc(ipadm_handle_t iph
, const void *arg
,
935 ipadm_prop_desc_t
*ipd
, char *buf
, uint_t
*bufsize
, uint_t proto
,
939 const char *ifname
= arg
;
941 char if_name
[IF_NAMESIZE
];
946 nbytes
= snprintf(buf
, *bufsize
, "%d", MOD_PROP_PERM_RW
);
948 case MOD_PROP_DEFAULT
:
949 nbytes
= snprintf(buf
, *bufsize
, "%s", IPADM_NONESTR
);
951 case MOD_PROP_ACTIVE
:
952 bzero(&lifr
, sizeof (lifr
));
953 (void) strlcpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
955 s
= (proto
== MOD_PROTO_IPV6
? iph
->iph_sock6
: iph
->iph_sock
);
956 if (ioctl(s
, SIOCGLIFUSESRC
, (caddr_t
)&lifr
) < 0)
957 return (ipadm_errno2status(errno
));
958 if (lifr
.lifr_index
== 0) {
959 /* no src address was set, so print 'none' */
960 (void) strlcpy(if_name
, IPADM_NONESTR
,
962 } else if (if_indextoname(lifr
.lifr_index
, if_name
) == NULL
) {
963 return (ipadm_errno2status(errno
));
965 nbytes
= snprintf(buf
, *bufsize
, "%s", if_name
);
968 return (IPADM_INVALID_ARG
);
970 if (nbytes
>= *bufsize
) {
971 /* insufficient buffer space */
972 *bufsize
= nbytes
+ 1;
973 return (IPADM_NO_BUFS
);
975 return (IPADM_SUCCESS
);
979 static ipadm_status_t
980 i_ipadm_get_ifprop_flags(ipadm_handle_t iph
, const void *arg
,
981 ipadm_prop_desc_t
*pdp
, char *buf
, uint_t
*bufsize
, uint_t proto
,
987 const char *ifname
= arg
;
989 ipadm_status_t status
= IPADM_SUCCESS
;
993 nbytes
= snprintf(buf
, *bufsize
, "%d", MOD_PROP_PERM_RW
);
995 case MOD_PROP_DEFAULT
:
996 if (strcmp(pdp
->ipd_name
, "exchange_routes") == 0 ||
997 strcmp(pdp
->ipd_name
, "arp") == 0 ||
998 strcmp(pdp
->ipd_name
, "nud") == 0) {
1000 } else if (strcmp(pdp
->ipd_name
, "forwarding") == 0) {
1003 return (IPADM_PROP_UNKNOWN
);
1005 nbytes
= snprintf(buf
, *bufsize
, "%s", val
);
1007 case MOD_PROP_ACTIVE
:
1008 af
= (proto
== MOD_PROTO_IPV6
? AF_INET6
: AF_INET
);
1009 status
= i_ipadm_get_flags(iph
, ifname
, af
, &intf_flags
);
1010 if (status
!= IPADM_SUCCESS
)
1014 if (strcmp(pdp
->ipd_name
, "exchange_routes") == 0) {
1015 if (!(intf_flags
& IFF_NORTEXCH
))
1017 } else if (strcmp(pdp
->ipd_name
, "forwarding") == 0) {
1018 if (intf_flags
& IFF_ROUTER
)
1020 } else if (strcmp(pdp
->ipd_name
, "arp") == 0) {
1021 if (!(intf_flags
& IFF_NOARP
))
1023 } else if (strcmp(pdp
->ipd_name
, "nud") == 0) {
1024 if (!(intf_flags
& IFF_NONUD
))
1027 nbytes
= snprintf(buf
, *bufsize
, "%s", val
);
1030 return (IPADM_INVALID_ARG
);
1032 if (nbytes
>= *bufsize
) {
1033 /* insufficient buffer space */
1034 *bufsize
= nbytes
+ 1;
1035 status
= IPADM_NO_BUFS
;
1042 i_ipadm_perm2str(char *buf
, uint_t
*bufsize
)
1044 uint_t perm
= atoi(buf
);
1046 (void) snprintf(buf
, *bufsize
, "%c%c",
1047 ((perm
& MOD_PROP_PERM_READ
) != 0) ? 'r' : '-',
1048 ((perm
& MOD_PROP_PERM_WRITE
) != 0) ? 'w' : '-');
1052 static ipadm_status_t
1053 i_ipadm_get_prop(ipadm_handle_t iph
, const void *arg
,
1054 ipadm_prop_desc_t
*pdp
, char *buf
, uint_t
*bufsize
, uint_t proto
,
1057 ipadm_status_t status
= IPADM_SUCCESS
;
1058 const char *ifname
= arg
;
1059 mod_ioc_prop_t
*mip
;
1060 char *pname
= pdp
->ipd_name
;
1063 /* allocate sufficient ioctl buffer to retrieve value */
1064 iocsize
= sizeof (mod_ioc_prop_t
) + *bufsize
- 1;
1065 if ((mip
= calloc(1, iocsize
)) == NULL
)
1066 return (IPADM_NO_BUFS
);
1068 mip
->mpr_version
= MOD_PROP_VERSION
;
1069 mip
->mpr_flags
= valtype
;
1070 mip
->mpr_proto
= proto
;
1071 if (ifname
!= NULL
) {
1072 (void) strlcpy(mip
->mpr_ifname
, ifname
,
1073 sizeof (mip
->mpr_ifname
));
1075 (void) strlcpy(mip
->mpr_name
, pname
, sizeof (mip
->mpr_name
));
1076 mip
->mpr_valsize
= *bufsize
;
1078 if (i_ipadm_strioctl(iph
->iph_sock
, SIOCGETPROP
, (char *)mip
,
1080 if (errno
== ENOENT
)
1081 status
= IPADM_PROP_UNKNOWN
;
1083 status
= ipadm_errno2status(errno
);
1085 bcopy(mip
->mpr_val
, buf
, *bufsize
);
1093 * Populates the ipmgmt_prop_arg_t based on the class of property.
1095 * For private protocol properties, while persisting information in ipadm
1096 * data store, to ensure there is no collision of namespace between ipadm
1097 * private nvpair names (which also starts with '_', see ipadm_ipmgmt.h)
1098 * and private protocol property names, we will prepend IPADM_PRIV_PROP_PREFIX
1099 * to property names.
1102 i_ipadm_populate_proparg(ipmgmt_prop_arg_t
*pargp
, ipadm_prop_desc_t
*pdp
,
1103 const char *pval
, const void *object
)
1105 const struct ipadm_addrobj_s
*ipaddr
;
1106 uint_t
class = pdp
->ipd_class
;
1107 uint_t proto
= pdp
->ipd_proto
;
1109 (void) strlcpy(pargp
->ia_pname
, pdp
->ipd_name
,
1110 sizeof (pargp
->ia_pname
));
1112 (void) strlcpy(pargp
->ia_pval
, pval
, sizeof (pargp
->ia_pval
));
1115 case IPADMPROP_CLASS_MODULE
:
1116 /* if it's a private property then add the prefix. */
1117 if (pdp
->ipd_name
[0] == '_') {
1118 (void) snprintf(pargp
->ia_pname
,
1119 sizeof (pargp
->ia_pname
), "_%s", pdp
->ipd_name
);
1121 (void) strlcpy(pargp
->ia_module
, object
,
1122 sizeof (pargp
->ia_module
));
1124 case IPADMPROP_CLASS_MODIF
:
1125 /* check if object is protostr or an ifname */
1126 if (ipadm_str2proto(object
) != MOD_PROTO_NONE
) {
1127 (void) strlcpy(pargp
->ia_module
, object
,
1128 sizeof (pargp
->ia_module
));
1131 /* it's an interface property, fall through */
1133 case IPADMPROP_CLASS_IF
:
1134 (void) strlcpy(pargp
->ia_ifname
, object
,
1135 sizeof (pargp
->ia_ifname
));
1136 (void) strlcpy(pargp
->ia_module
, ipadm_proto2str(proto
),
1137 sizeof (pargp
->ia_module
));
1139 case IPADMPROP_CLASS_ADDR
:
1141 (void) strlcpy(pargp
->ia_ifname
, ipaddr
->ipadm_ifname
,
1142 sizeof (pargp
->ia_ifname
));
1143 (void) strlcpy(pargp
->ia_aobjname
, ipaddr
->ipadm_aobjname
,
1144 sizeof (pargp
->ia_aobjname
));
1150 * Common function to retrieve property value for a given interface `ifname' or
1151 * for a given protocol `proto'. The property name is in `pname'.
1153 * `valtype' determines the type of value that will be retrieved.
1154 * IPADM_OPT_ACTIVE - current value of the property (active config)
1155 * IPADM_OPT_PERSIST - value of the property from persistent store
1156 * IPADM_OPT_DEFAULT - default hard coded value (boot-time value)
1157 * IPADM_OPT_PERM - read/write permissions for the value
1158 * IPADM_OPT_POSSIBLE - range of values
1160 static ipadm_status_t
1161 i_ipadm_getprop_common(ipadm_handle_t iph
, const char *ifname
,
1162 const char *pname
, char *buf
, uint_t
*bufsize
, uint_t proto
,
1165 ipadm_status_t status
= IPADM_SUCCESS
;
1166 ipadm_prop_desc_t
*pdp
;
1167 char priv_propname
[MAXPROPNAMELEN
];
1168 boolean_t is_if
= (ifname
!= NULL
);
1171 pdp
= i_ipadm_get_prop_desc(pname
, proto
, &err
);
1173 return (IPADM_BAD_PROTOCOL
);
1174 /* there are no private interface properties */
1175 if (is_if
&& err
== ENOENT
)
1176 return (IPADM_PROP_UNKNOWN
);
1180 * check whether the property can be
1181 * applied on an interface
1183 if (is_if
&& !(pdp
->ipd_class
& IPADMPROP_CLASS_IF
))
1184 return (IPADM_INVALID_ARG
);
1186 * check whether the property can be
1187 * applied on a module
1189 if (!is_if
&& !(pdp
->ipd_class
& IPADMPROP_CLASS_MODULE
))
1190 return (IPADM_INVALID_ARG
);
1193 /* private protocol properties, pass it to kernel directly */
1194 pdp
= &ipadm_privprop
;
1195 (void) strlcpy(priv_propname
, pname
, sizeof (priv_propname
));
1196 pdp
->ipd_name
= priv_propname
;
1200 case IPADM_OPT_PERM
:
1201 status
= pdp
->ipd_get(iph
, ifname
, pdp
, buf
, bufsize
, proto
,
1203 if (status
== IPADM_SUCCESS
)
1204 i_ipadm_perm2str(buf
, bufsize
);
1206 case IPADM_OPT_ACTIVE
:
1207 status
= pdp
->ipd_get(iph
, ifname
, pdp
, buf
, bufsize
, proto
,
1210 case IPADM_OPT_DEFAULT
:
1211 status
= pdp
->ipd_get(iph
, ifname
, pdp
, buf
, bufsize
, proto
,
1214 case IPADM_OPT_POSSIBLE
:
1215 if (pdp
->ipd_get_range
!= NULL
) {
1216 status
= pdp
->ipd_get_range(iph
, ifname
, pdp
, buf
,
1217 bufsize
, proto
, MOD_PROP_POSSIBLE
);
1222 case IPADM_OPT_PERSIST
:
1223 /* retrieve from database */
1225 status
= i_ipadm_get_persist_propval(iph
, pdp
, buf
,
1228 status
= i_ipadm_get_persist_propval(iph
, pdp
, buf
,
1229 bufsize
, ipadm_proto2str(proto
));
1232 status
= IPADM_INVALID_ARG
;
1239 * Get protocol property of the specified protocol.
1242 ipadm_get_prop(ipadm_handle_t iph
, const char *pname
, char *buf
,
1243 uint_t
*bufsize
, uint_t proto
, uint_t valtype
)
1246 * validate the arguments of the function.
1248 if (iph
== NULL
|| pname
== NULL
|| buf
== NULL
||
1249 bufsize
== NULL
|| *bufsize
== 0) {
1250 return (IPADM_INVALID_ARG
);
1253 * Do we support this proto, if not return error.
1255 if (ipadm_proto2str(proto
) == NULL
)
1256 return (IPADM_NOTSUP
);
1258 return (i_ipadm_getprop_common(iph
, NULL
, pname
, buf
, bufsize
,
1263 * Get interface property of the specified interface.
1266 ipadm_get_ifprop(ipadm_handle_t iph
, const char *ifname
, const char *pname
,
1267 char *buf
, uint_t
*bufsize
, uint_t proto
, uint_t valtype
)
1269 /* validate the arguments of the function. */
1270 if (iph
== NULL
|| pname
== NULL
|| buf
== NULL
||
1271 bufsize
== NULL
|| *bufsize
== 0) {
1272 return (IPADM_INVALID_ARG
);
1275 /* Do we support this proto, if not return error. */
1276 if (ipadm_proto2str(proto
) == NULL
)
1277 return (IPADM_NOTSUP
);
1280 * check if interface name is provided for interface property and
1283 if (!i_ipadm_validate_ifname(iph
, ifname
))
1284 return (IPADM_INVALID_ARG
);
1286 return (i_ipadm_getprop_common(iph
, ifname
, pname
, buf
, bufsize
,
1291 * Allocates sufficient ioctl buffers and copies property name and the
1292 * value, among other things. If the flag IPADM_OPT_DEFAULT is set, then
1293 * `pval' will be NULL and it instructs the kernel to reset the current
1294 * value to property's default value.
1296 static ipadm_status_t
1297 i_ipadm_set_prop(ipadm_handle_t iph
, const void *arg
,
1298 ipadm_prop_desc_t
*pdp
, const void *pval
, uint_t proto
, uint_t flags
)
1300 ipadm_status_t status
= IPADM_SUCCESS
;
1301 const char *ifname
= arg
;
1302 mod_ioc_prop_t
*mip
;
1303 char *pname
= pdp
->ipd_name
;
1304 uint_t valsize
, iocsize
;
1305 uint_t iocflags
= 0;
1307 if (flags
& IPADM_OPT_DEFAULT
) {
1308 iocflags
|= MOD_PROP_DEFAULT
;
1309 } else if (flags
& IPADM_OPT_ACTIVE
) {
1310 iocflags
|= MOD_PROP_ACTIVE
;
1311 if (flags
& IPADM_OPT_APPEND
)
1312 iocflags
|= MOD_PROP_APPEND
;
1313 else if (flags
& IPADM_OPT_REMOVE
)
1314 iocflags
|= MOD_PROP_REMOVE
;
1318 valsize
= strlen(pval
);
1319 iocsize
= sizeof (mod_ioc_prop_t
) + valsize
- 1;
1322 iocsize
= sizeof (mod_ioc_prop_t
);
1325 if ((mip
= calloc(1, iocsize
)) == NULL
)
1326 return (IPADM_NO_BUFS
);
1328 mip
->mpr_version
= MOD_PROP_VERSION
;
1329 mip
->mpr_flags
= iocflags
;
1330 mip
->mpr_proto
= proto
;
1331 if (ifname
!= NULL
) {
1332 (void) strlcpy(mip
->mpr_ifname
, ifname
,
1333 sizeof (mip
->mpr_ifname
));
1336 (void) strlcpy(mip
->mpr_name
, pname
, sizeof (mip
->mpr_name
));
1337 mip
->mpr_valsize
= valsize
;
1339 bcopy(pval
, mip
->mpr_val
, valsize
);
1341 if (i_ipadm_strioctl(iph
->iph_sock
, SIOCSETPROP
, (char *)mip
,
1343 if (errno
== ENOENT
)
1344 status
= IPADM_PROP_UNKNOWN
;
1346 status
= ipadm_errno2status(errno
);
1353 * Common function for modifying both protocol/interface property.
1356 * IPADM_OPT_PERSIST is set then the value is persisted.
1357 * IPADM_OPT_DEFAULT is set then the default value for the property will
1360 static ipadm_status_t
1361 i_ipadm_setprop_common(ipadm_handle_t iph
, const char *ifname
,
1362 const char *pname
, const char *buf
, uint_t proto
, uint_t pflags
)
1364 ipadm_status_t status
= IPADM_SUCCESS
;
1365 boolean_t persist
= (pflags
& IPADM_OPT_PERSIST
);
1366 boolean_t reset
= (pflags
& IPADM_OPT_DEFAULT
);
1367 ipadm_prop_desc_t
*pdp
;
1368 boolean_t is_if
= (ifname
!= NULL
);
1369 char priv_propname
[MAXPROPNAMELEN
];
1372 /* Check that property value is within the allowed size */
1373 if (!reset
&& strnlen(buf
, MAXPROPVALLEN
) >= MAXPROPVALLEN
)
1374 return (IPADM_INVALID_ARG
);
1376 pdp
= i_ipadm_get_prop_desc(pname
, proto
, &err
);
1378 return (IPADM_BAD_PROTOCOL
);
1379 /* there are no private interface properties */
1380 if (is_if
&& err
== ENOENT
)
1381 return (IPADM_PROP_UNKNOWN
);
1384 /* do some sanity checks */
1386 if (!(pdp
->ipd_class
& IPADMPROP_CLASS_IF
))
1387 return (IPADM_INVALID_ARG
);
1389 if (!(pdp
->ipd_class
& IPADMPROP_CLASS_MODULE
))
1390 return (IPADM_INVALID_ARG
);
1393 * if the property is not multi-valued and IPADM_OPT_APPEND or
1394 * IPADM_OPT_REMOVE is specified, return IPADM_INVALID_ARG.
1396 if (!(pdp
->ipd_flags
& IPADMPROP_MULVAL
) && (pflags
&
1397 (IPADM_OPT_APPEND
|IPADM_OPT_REMOVE
))) {
1398 return (IPADM_INVALID_ARG
);
1401 /* private protocol property, pass it to kernel directly */
1402 pdp
= &ipadm_privprop
;
1403 (void) strlcpy(priv_propname
, pname
, sizeof (priv_propname
));
1404 pdp
->ipd_name
= priv_propname
;
1407 status
= pdp
->ipd_set(iph
, ifname
, pdp
, buf
, proto
, pflags
);
1408 if (status
!= IPADM_SUCCESS
)
1413 status
= i_ipadm_persist_propval(iph
, pdp
, buf
, ifname
,
1416 status
= i_ipadm_persist_propval(iph
, pdp
, buf
,
1417 ipadm_proto2str(proto
), pflags
);
1423 * Sets the property value of the specified interface
1426 ipadm_set_ifprop(ipadm_handle_t iph
, const char *ifname
, const char *pname
,
1427 const char *buf
, uint_t proto
, uint_t pflags
)
1429 boolean_t reset
= (pflags
& IPADM_OPT_DEFAULT
);
1430 ipadm_status_t status
;
1432 /* check for solaris.network.interface.config authorization */
1433 if (!ipadm_check_auth())
1434 return (IPADM_EAUTH
);
1436 * validate the arguments of the function.
1438 if (iph
== NULL
|| pname
== NULL
|| (!reset
&& buf
== NULL
) ||
1439 pflags
== 0 || pflags
== IPADM_OPT_PERSIST
||
1440 (pflags
& ~(IPADM_COMMON_OPT_MASK
|IPADM_OPT_DEFAULT
))) {
1441 return (IPADM_INVALID_ARG
);
1445 * Do we support this protocol, if not return error.
1447 if (ipadm_proto2str(proto
) == NULL
)
1448 return (IPADM_NOTSUP
);
1451 * Validate the interface and check if a persistent
1452 * operation is performed on a temporary object.
1454 status
= i_ipadm_validate_if(iph
, ifname
, proto
, pflags
);
1455 if (status
!= IPADM_SUCCESS
)
1458 return (i_ipadm_setprop_common(iph
, ifname
, pname
, buf
, proto
,
1463 * Sets the property value of the specified protocol.
1466 ipadm_set_prop(ipadm_handle_t iph
, const char *pname
, const char *buf
,
1467 uint_t proto
, uint_t pflags
)
1469 boolean_t reset
= (pflags
& IPADM_OPT_DEFAULT
);
1471 /* check for solaris.network.interface.config authorization */
1472 if (!ipadm_check_auth())
1473 return (IPADM_EAUTH
);
1475 * validate the arguments of the function.
1477 if (iph
== NULL
|| pname
== NULL
||(!reset
&& buf
== NULL
) ||
1478 pflags
== 0 || pflags
== IPADM_OPT_PERSIST
||
1479 (pflags
& ~(IPADM_COMMON_OPT_MASK
|IPADM_OPT_DEFAULT
|
1480 IPADM_OPT_APPEND
|IPADM_OPT_REMOVE
))) {
1481 return (IPADM_INVALID_ARG
);
1485 * Do we support this proto, if not return error.
1487 if (ipadm_proto2str(proto
) == NULL
)
1488 return (IPADM_NOTSUP
);
1490 return (i_ipadm_setprop_common(iph
, NULL
, pname
, buf
, proto
,
1494 /* helper function for ipadm_walk_proptbl */
1496 i_ipadm_walk_proptbl(ipadm_prop_desc_t
*pdtbl
, uint_t proto
, uint_t
class,
1497 ipadm_prop_wfunc_t
*func
, void *arg
)
1499 ipadm_prop_desc_t
*pdp
;
1501 for (pdp
= pdtbl
; pdp
->ipd_name
!= NULL
; pdp
++) {
1502 if (!(pdp
->ipd_class
& class))
1505 if (proto
!= MOD_PROTO_NONE
&& !(pdp
->ipd_proto
& proto
))
1509 * we found a class specific match, call the
1510 * user callback function.
1512 if (func(arg
, pdp
->ipd_name
, pdp
->ipd_proto
) == B_FALSE
)
1518 * Walks through all the properties, for a given protocol and property class
1519 * (protocol or interface).
1521 * Further if proto == MOD_PROTO_NONE, then it walks through all the supported
1522 * protocol property tables.
1525 ipadm_walk_proptbl(uint_t proto
, uint_t
class, ipadm_prop_wfunc_t
*func
,
1528 ipadm_prop_desc_t
*pdtbl
;
1529 ipadm_status_t status
= IPADM_SUCCESS
;
1531 int count
= A_CNT(protocols
);
1534 return (IPADM_INVALID_ARG
);
1537 case IPADMPROP_CLASS_ADDR
:
1538 pdtbl
= ipadm_addrprop_table
;
1540 case IPADMPROP_CLASS_IF
:
1541 case IPADMPROP_CLASS_MODULE
:
1542 pdtbl
= i_ipadm_get_propdesc_table(proto
);
1543 if (pdtbl
== NULL
&& proto
!= MOD_PROTO_NONE
)
1544 return (IPADM_INVALID_ARG
);
1547 return (IPADM_INVALID_ARG
);
1550 if (pdtbl
!= NULL
) {
1552 * proto will be MOD_PROTO_NONE in the case of
1553 * IPADMPROP_CLASS_ADDR.
1555 i_ipadm_walk_proptbl(pdtbl
, proto
, class, func
, arg
);
1557 /* Walk thru all the protocol tables, we support */
1558 for (i
= 0; i
< count
; i
++) {
1559 pdtbl
= i_ipadm_get_propdesc_table(protocols
[i
]);
1560 i_ipadm_walk_proptbl(pdtbl
, protocols
[i
], class, func
,
1568 * Given a property name, walks through all the instances of a property name.
1569 * Some properties have two instances one for v4 interfaces and another for v6
1570 * interfaces. For example: MTU. MTU can have different values for v4 and v6.
1571 * Therefore there are two properties for 'MTU'.
1573 * This function invokes `func' for every instance of property `pname'
1576 ipadm_walk_prop(const char *pname
, uint_t proto
, uint_t
class,
1577 ipadm_prop_wfunc_t
*func
, void *arg
)
1579 ipadm_prop_desc_t
*pdtbl
, *pdp
;
1580 ipadm_status_t status
= IPADM_SUCCESS
;
1581 boolean_t matched
= B_FALSE
;
1583 if (pname
== NULL
|| func
== NULL
)
1584 return (IPADM_INVALID_ARG
);
1587 case IPADMPROP_CLASS_ADDR
:
1588 pdtbl
= ipadm_addrprop_table
;
1590 case IPADMPROP_CLASS_IF
:
1591 case IPADMPROP_CLASS_MODULE
:
1592 pdtbl
= i_ipadm_get_propdesc_table(proto
);
1595 return (IPADM_INVALID_ARG
);
1599 return (IPADM_INVALID_ARG
);
1601 for (pdp
= pdtbl
; pdp
->ipd_name
!= NULL
; pdp
++) {
1602 if (strcmp(pname
, pdp
->ipd_name
) != 0)
1604 if (!(pdp
->ipd_proto
& proto
))
1607 /* we found a match, call the callback function */
1608 if (func(arg
, pdp
->ipd_name
, pdp
->ipd_proto
) == B_FALSE
)
1612 status
= IPADM_PROP_UNKNOWN
;
1618 i_ipadm_get_onoff(ipadm_handle_t iph
, const void *arg
, ipadm_prop_desc_t
*dp
,
1619 char *buf
, uint_t
*bufsize
, uint_t proto
, uint_t valtype
)
1621 (void) snprintf(buf
, *bufsize
, "%s,%s", IPADM_ONSTR
, IPADM_OFFSTR
);
1622 return (IPADM_SUCCESS
);
1626 * Makes a door call to ipmgmtd to retrieve the persisted property value
1629 i_ipadm_get_persist_propval(ipadm_handle_t iph
, ipadm_prop_desc_t
*pdp
,
1630 char *gbuf
, uint_t
*gbufsize
, const void *object
)
1632 ipmgmt_prop_arg_t parg
;
1633 ipmgmt_getprop_rval_t rval
, *rvalp
;
1637 bzero(&parg
, sizeof (parg
));
1638 parg
.ia_cmd
= IPMGMT_CMD_GETPROP
;
1639 i_ipadm_populate_proparg(&parg
, pdp
, NULL
, object
);
1642 err
= ipadm_door_call(iph
, &parg
, sizeof (parg
), (void **)&rvalp
,
1643 sizeof (rval
), B_FALSE
);
1645 /* assert that rvalp was not reallocated */
1646 assert(rvalp
== &rval
);
1648 /* `ir_pval' contains the property value */
1649 nbytes
= snprintf(gbuf
, *gbufsize
, "%s", rvalp
->ir_pval
);
1650 if (nbytes
>= *gbufsize
) {
1651 /* insufficient buffer space */
1652 *gbufsize
= nbytes
+ 1;
1656 return (ipadm_errno2status(err
));
1660 * Persists the property value for a given property in the data store
1663 i_ipadm_persist_propval(ipadm_handle_t iph
, ipadm_prop_desc_t
*pdp
,
1664 const char *pval
, const void *object
, uint_t flags
)
1666 ipmgmt_prop_arg_t parg
;
1669 bzero(&parg
, sizeof (parg
));
1670 i_ipadm_populate_proparg(&parg
, pdp
, pval
, object
);
1672 * Check if value to be persisted need to be appended or removed. This
1673 * is required for multi-valued property.
1675 if (flags
& IPADM_OPT_APPEND
)
1676 parg
.ia_flags
|= IPMGMT_APPEND
;
1677 if (flags
& IPADM_OPT_REMOVE
)
1678 parg
.ia_flags
|= IPMGMT_REMOVE
;
1680 if (flags
& (IPADM_OPT_DEFAULT
|IPADM_OPT_REMOVE
))
1681 parg
.ia_cmd
= IPMGMT_CMD_RESETPROP
;
1683 parg
.ia_cmd
= IPMGMT_CMD_SETPROP
;
1685 err
= ipadm_door_call(iph
, &parg
, sizeof (parg
), NULL
, 0, B_FALSE
);
1688 * its fine if there were no entry in the DB to delete. The user
1689 * might be changing property value, which was not changed
1694 return (ipadm_errno2status(err
));
1698 * This is called from ipadm_set_ifprop() to validate the set operation.
1699 * It does the following steps:
1700 * 1. Validates the interface name.
1701 * 2. Fails if it is an IPMP meta-interface or an underlying interface.
1702 * 3. In case of a persistent operation, verifies that the
1703 * interface is persistent.
1705 static ipadm_status_t
1706 i_ipadm_validate_if(ipadm_handle_t iph
, const char *ifname
,
1707 uint_t proto
, uint_t flags
)
1709 sa_family_t af
, other_af
;
1710 ipadm_status_t status
;
1712 boolean_t af_exists
, other_af_exists
, a_exists
;
1714 /* Check if the interface name is valid. */
1715 if (!i_ipadm_validate_ifname(iph
, ifname
))
1716 return (IPADM_INVALID_ARG
);
1718 af
= (proto
== MOD_PROTO_IPV6
? AF_INET6
: AF_INET
);
1720 * Setting properties on an IPMP meta-interface or underlying
1721 * interface is not supported.
1723 if (i_ipadm_is_ipmp(iph
, ifname
) || i_ipadm_is_under_ipmp(iph
, ifname
))
1724 return (IPADM_NOTSUP
);
1726 /* Check if interface exists in the persistent configuration. */
1727 status
= i_ipadm_if_pexists(iph
, ifname
, af
, &p_exists
);
1728 if (status
!= IPADM_SUCCESS
)
1731 /* Check if interface exists in the active configuration. */
1732 af_exists
= ipadm_if_enabled(iph
, ifname
, af
);
1733 other_af
= (af
== AF_INET
? AF_INET6
: AF_INET
);
1734 other_af_exists
= ipadm_if_enabled(iph
, ifname
, other_af
);
1735 a_exists
= (af_exists
|| other_af_exists
);
1736 if (!a_exists
&& p_exists
)
1737 return (IPADM_OP_DISABLE_OBJ
);
1739 return (IPADM_ENXIO
);
1742 * If a persistent operation is requested, check if the underlying
1743 * IP interface is persistent.
1745 if ((flags
& IPADM_OPT_PERSIST
) && !p_exists
)
1746 return (IPADM_TEMPORARY_OBJ
);
1747 return (IPADM_SUCCESS
);
1751 * Private protocol properties namespace scheme:
1753 * PSARC 2010/080 identified the private protocol property names to be the
1754 * leading protocol names. For e.g. tcp_strong_iss, ip_strict_src_multihoming,
1755 * et al,. However to be consistent with private data-link property names,
1756 * which starts with '_', private protocol property names will start with '_'.
1757 * For e.g. _strong_iss, _strict_src_multihoming, et al,.
1760 /* maps new private protocol property name to the old private property name */
1761 typedef struct ipadm_oname2nname_map
{
1765 } ipadm_oname2nname_map_t
;
1768 * IP is a special case. It isn't straight forward to derive the legacy name
1769 * from the new name and vice versa. No set standard was followed in naming
1770 * the properties and hence we need a table to capture the mapping.
1772 static ipadm_oname2nname_map_t name_map
[] = {
1773 { "arp_probe_delay", "_arp_probe_delay",
1775 { "arp_fastprobe_delay", "_arp_fastprobe_delay",
1777 { "arp_probe_interval", "_arp_probe_interval",
1779 { "arp_fastprobe_interval", "_arp_fastprobe_interval",
1781 { "arp_probe_count", "_arp_probe_count",
1783 { "arp_fastprobe_count", "_arp_fastprobe_count",
1785 { "arp_defend_interval", "_arp_defend_interval",
1787 { "arp_defend_rate", "_arp_defend_rate",
1789 { "arp_defend_period", "_arp_defend_period",
1791 { "ndp_defend_interval", "_ndp_defend_interval",
1793 { "ndp_defend_rate", "_ndp_defend_rate",
1795 { "ndp_defend_period", "_ndp_defend_period",
1797 { "igmp_max_version", "_igmp_max_version",
1799 { "mld_max_version", "_mld_max_version",
1801 { "ipsec_override_persocket_policy", "_ipsec_override_persocket_policy",
1803 { "ipsec_policy_log_interval", "_ipsec_policy_log_interval",
1805 { "icmp_accept_clear_messages", "_icmp_accept_clear_messages",
1807 { "igmp_accept_clear_messages", "_igmp_accept_clear_messages",
1809 { "pim_accept_clear_messages", "_pim_accept_clear_messages",
1811 { "ip_respond_to_echo_multicast", "_respond_to_echo_multicast",
1813 { "ip_send_redirects", "_send_redirects",
1815 { "ip_forward_src_routed", "_forward_src_routed",
1817 { "ip_icmp_return_data_bytes", "_icmp_return_data_bytes",
1819 { "ip_ignore_redirect", "_ignore_redirect",
1821 { "ip_strict_dst_multihoming", "_strict_dst_multihoming",
1823 { "ip_reasm_timeout", "_reasm_timeout",
1825 { "ip_strict_src_multihoming", "_strict_src_multihoming",
1827 { "ipv4_dad_announce_interval", "_dad_announce_interval",
1829 { "ipv4_icmp_return_pmtu", "_icmp_return_pmtu",
1831 { "ipv6_dad_announce_interval", "_dad_announce_interval",
1833 { "ipv6_icmp_return_pmtu", "_icmp_return_pmtu",
1835 { NULL
, NULL
, MOD_PROTO_NONE
}
1839 * Following API returns a new property name in `nname' for the given legacy
1840 * property name in `oname'.
1843 ipadm_legacy2new_propname(const char *oname
, char *nname
, uint_t nnamelen
,
1847 ipadm_oname2nname_map_t
*ionmp
;
1849 /* if it's a public property, there is nothing to return */
1850 if (i_ipadm_get_prop_desc(oname
, *proto
, NULL
) != NULL
)
1854 * we didn't find the `oname' in the table, check if the property
1855 * name begins with a leading protocol.
1860 if (strstr(oname
, "tcp_") == oname
)
1861 str
+= strlen("tcp");
1863 case MOD_PROTO_SCTP
:
1864 if (strstr(oname
, "sctp_") == oname
)
1865 str
+= strlen("sctp");
1868 if (strstr(oname
, "udp_") == oname
)
1869 str
+= strlen("udp");
1871 case MOD_PROTO_RAWIP
:
1872 if (strstr(oname
, "icmp_") == oname
)
1873 str
+= strlen("icmp");
1876 case MOD_PROTO_IPV4
:
1877 case MOD_PROTO_IPV6
:
1878 if (strstr(oname
, "ip6_") == oname
) {
1879 *proto
= MOD_PROTO_IPV6
;
1880 str
+= strlen("ip6");
1882 for (ionmp
= name_map
; ionmp
->iom_oname
!= NULL
;
1884 if (strcmp(oname
, ionmp
->iom_oname
) == 0) {
1885 str
= ionmp
->iom_nname
;
1886 *proto
= ionmp
->iom_proto
;
1890 if (ionmp
->iom_oname
!= NULL
)
1893 if (strstr(oname
, "ip_") == oname
) {
1894 *proto
= MOD_PROTO_IP
;
1895 str
+= strlen("ip");
1902 (void) snprintf(nname
, nnamelen
, "%s", str
);
1907 * Following API is required for ndd.c alone. To maintain backward
1908 * compatibility with ndd output, we need to print the legacy name
1912 ipadm_new2legacy_propname(const char *oname
, char *nname
,
1913 uint_t nnamelen
, uint_t proto
)
1916 ipadm_oname2nname_map_t
*ionmp
;
1918 /* if it's a public property, there is nothing to prepend */
1919 if (i_ipadm_get_prop_desc(oname
, proto
, NULL
) != NULL
)
1926 case MOD_PROTO_SCTP
:
1932 case MOD_PROTO_RAWIP
:
1936 case MOD_PROTO_IPV4
:
1937 case MOD_PROTO_IPV6
:
1938 /* handle special case for IP */
1939 for (ionmp
= name_map
; ionmp
->iom_oname
!= NULL
; ionmp
++) {
1940 if (strcmp(oname
, ionmp
->iom_nname
) == 0 &&
1941 ionmp
->iom_proto
== proto
) {
1942 (void) strlcpy(nname
, ionmp
->iom_oname
,
1947 if (proto
== MOD_PROTO_IPV6
)
1955 (void) snprintf(nname
, nnamelen
, "%s%s", prefix
, oname
);