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 { "dupack_fast_retrans", "dupack_fast_retransmit",
157 IPADMPROP_CLASS_MODULE
, MOD_PROTO_TCP
, 0, i_ipadm_set_prop
,
158 i_ipadm_get_prop
, i_ipadm_get_prop
},
160 { "ecn", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_TCP
, 0,
161 i_ipadm_set_ecnsack
, i_ipadm_get_ecnsack
, i_ipadm_get_ecnsack
},
163 { "extra_priv_ports", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_TCP
,
164 IPADMPROP_MULVAL
, i_ipadm_set_eprivport
, i_ipadm_get_prop
,
167 { "largest_anon_port", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_TCP
, 0,
168 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
170 { "max_buf", "_max_buf", IPADMPROP_CLASS_MODULE
, MOD_PROTO_TCP
, 0,
171 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
173 { "recv_buf", "recv_maxbuf", IPADMPROP_CLASS_MODULE
, MOD_PROTO_TCP
, 0,
174 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
176 { "sack", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_TCP
, 0,
177 i_ipadm_set_ecnsack
, i_ipadm_get_ecnsack
, i_ipadm_get_ecnsack
},
179 { "send_buf", "send_maxbuf", IPADMPROP_CLASS_MODULE
, MOD_PROTO_TCP
, 0,
180 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
182 { "smallest_anon_port", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_TCP
, 0,
183 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
185 { "smallest_nonpriv_port", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_TCP
,
186 0, i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
188 { NULL
, NULL
, 0, 0, 0, NULL
, NULL
, NULL
}
191 /* Supported UDP protocol properties */
192 static ipadm_prop_desc_t ipadm_udp_prop_table
[] = {
193 { "extra_priv_ports", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_UDP
,
194 IPADMPROP_MULVAL
, i_ipadm_set_eprivport
, i_ipadm_get_prop
,
197 { "largest_anon_port", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_UDP
, 0,
198 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
200 { "max_buf", "_max_buf", IPADMPROP_CLASS_MODULE
, MOD_PROTO_UDP
, 0,
201 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
203 { "recv_buf", "recv_maxbuf", IPADMPROP_CLASS_MODULE
, MOD_PROTO_UDP
, 0,
204 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
206 { "send_buf", "send_maxbuf", IPADMPROP_CLASS_MODULE
, MOD_PROTO_UDP
, 0,
207 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
209 { "smallest_anon_port", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_UDP
, 0,
210 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
212 { "smallest_nonpriv_port", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_UDP
,
213 0, i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
215 { NULL
, NULL
, 0, 0, 0, NULL
, NULL
, NULL
}
218 /* Supported SCTP protocol properties */
219 static ipadm_prop_desc_t ipadm_sctp_prop_table
[] = {
220 { "extra_priv_ports", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_SCTP
,
221 IPADMPROP_MULVAL
, i_ipadm_set_eprivport
, i_ipadm_get_prop
,
224 { "largest_anon_port", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_SCTP
, 0,
225 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
227 { "max_buf", "_max_buf", IPADMPROP_CLASS_MODULE
, MOD_PROTO_SCTP
, 0,
228 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
230 { "recv_buf", "recv_maxbuf", IPADMPROP_CLASS_MODULE
, MOD_PROTO_SCTP
, 0,
231 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
233 { "send_buf", "send_maxbuf", IPADMPROP_CLASS_MODULE
, MOD_PROTO_SCTP
, 0,
234 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
236 { "smallest_anon_port", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_SCTP
, 0,
237 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
239 { "smallest_nonpriv_port", NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_SCTP
,
240 0, i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
242 { NULL
, NULL
, 0, 0, 0, NULL
, NULL
, NULL
}
245 /* Supported ICMP protocol properties */
246 static ipadm_prop_desc_t ipadm_icmp_prop_table
[] = {
247 { "max_buf", "_max_buf", IPADMPROP_CLASS_MODULE
, MOD_PROTO_RAWIP
, 0,
248 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
250 { "recv_buf", "recv_maxbuf", IPADMPROP_CLASS_MODULE
, MOD_PROTO_RAWIP
, 0,
251 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
253 { "send_buf", "send_maxbuf", IPADMPROP_CLASS_MODULE
, MOD_PROTO_RAWIP
, 0,
254 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
},
256 { NULL
, NULL
, 0, 0, 0, NULL
, NULL
, NULL
}
260 * A dummy private property structure, used while handling private
261 * protocol properties (properties not yet supported by libipadm).
263 static ipadm_prop_desc_t ipadm_privprop
=
264 { NULL
, NULL
, IPADMPROP_CLASS_MODULE
, MOD_PROTO_NONE
, 0,
265 i_ipadm_set_prop
, i_ipadm_get_prop
, i_ipadm_get_prop
};
268 * Returns the property description table, for the given protocol
270 static ipadm_prop_desc_t
*
271 i_ipadm_get_propdesc_table(uint_t proto
)
277 return (ipadm_ip_prop_table
);
278 case MOD_PROTO_RAWIP
:
279 return (ipadm_icmp_prop_table
);
281 return (ipadm_tcp_prop_table
);
283 return (ipadm_udp_prop_table
);
285 return (ipadm_sctp_prop_table
);
291 static ipadm_prop_desc_t
*
292 i_ipadm_get_prop_desc(const char *pname
, uint_t proto
, int *errp
)
295 boolean_t matched_name
= B_FALSE
;
296 ipadm_prop_desc_t
*ipdp
= NULL
, *ipdtbl
;
298 if ((ipdtbl
= i_ipadm_get_propdesc_table(proto
)) == NULL
) {
303 for (ipdp
= ipdtbl
; ipdp
->ipd_name
!= NULL
; ipdp
++) {
304 if (strcmp(pname
, ipdp
->ipd_name
) == 0 ||
305 (ipdp
->ipd_old_name
!= NULL
&&
306 strcmp(pname
, ipdp
->ipd_old_name
) == 0)) {
307 matched_name
= B_TRUE
;
308 if (ipdp
->ipd_proto
== proto
)
313 if (ipdp
->ipd_name
== NULL
) {
315 /* if we matched name, but failed protocol check */
327 ipadm_proto2str(uint_t proto
)
336 case MOD_PROTO_RAWIP
:
350 ipadm_str2proto(const char *protostr
)
352 if (protostr
== NULL
)
353 return (MOD_PROTO_NONE
);
354 if (strcmp(protostr
, "tcp") == 0)
355 return (MOD_PROTO_TCP
);
356 else if (strcmp(protostr
, "udp") == 0)
357 return (MOD_PROTO_UDP
);
358 else if (strcmp(protostr
, "ip") == 0)
359 return (MOD_PROTO_IP
);
360 else if (strcmp(protostr
, "ipv4") == 0)
361 return (MOD_PROTO_IPV4
);
362 else if (strcmp(protostr
, "ipv6") == 0)
363 return (MOD_PROTO_IPV6
);
364 else if (strcmp(protostr
, "icmp") == 0)
365 return (MOD_PROTO_RAWIP
);
366 else if (strcmp(protostr
, "sctp") == 0)
367 return (MOD_PROTO_SCTP
);
368 else if (strcmp(protostr
, "arp") == 0)
369 return (MOD_PROTO_IP
);
371 return (MOD_PROTO_NONE
);
375 static ipadm_status_t
376 i_ipadm_set_mtu(ipadm_handle_t iph
, const void *arg
,
377 ipadm_prop_desc_t
*pdp
, const void *pval
, uint_t proto
, uint_t flags
)
383 const char *ifname
= arg
;
384 char val
[MAXPROPVALLEN
];
386 /* to reset MTU first retrieve the default MTU and then set it */
387 if (flags
& IPADM_OPT_DEFAULT
) {
388 ipadm_status_t status
;
389 uint_t size
= MAXPROPVALLEN
;
391 status
= i_ipadm_get_prop(iph
, arg
, pdp
, val
, &size
,
392 proto
, MOD_PROP_DEFAULT
);
393 if (status
!= IPADM_SUCCESS
)
399 mtu
= (uint_t
)strtol(pval
, &endp
, 10);
400 if (errno
!= 0 || *endp
!= '\0')
401 return (IPADM_INVALID_ARG
);
403 bzero(&lifr
, sizeof (lifr
));
404 (void) strlcpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
407 s
= (proto
== MOD_PROTO_IPV6
? iph
->iph_sock6
: iph
->iph_sock
);
408 if (ioctl(s
, SIOCSLIFMTU
, (caddr_t
)&lifr
) < 0)
409 return (ipadm_errno2status(errno
));
411 return (IPADM_SUCCESS
);
415 static ipadm_status_t
416 i_ipadm_set_metric(ipadm_handle_t iph
, const void *arg
,
417 ipadm_prop_desc_t
*pdp
, const void *pval
, uint_t proto
, uint_t flags
)
422 const char *ifname
= arg
;
425 /* if we are resetting, set the value to its default value */
426 if (flags
& IPADM_OPT_DEFAULT
) {
427 metric
= DEF_METRIC_VAL
;
430 metric
= (uint_t
)strtol(pval
, &endp
, 10);
431 if (errno
!= 0 || *endp
!= '\0')
432 return (IPADM_INVALID_ARG
);
435 bzero(&lifr
, sizeof (lifr
));
436 (void) strlcpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
437 lifr
.lifr_metric
= metric
;
439 s
= (proto
== MOD_PROTO_IPV6
? iph
->iph_sock6
: iph
->iph_sock
);
441 if (ioctl(s
, SIOCSLIFMETRIC
, (caddr_t
)&lifr
) < 0)
442 return (ipadm_errno2status(errno
));
444 return (IPADM_SUCCESS
);
448 static ipadm_status_t
449 i_ipadm_set_usesrc(ipadm_handle_t iph
, const void *arg
,
450 ipadm_prop_desc_t
*pdp
, const void *pval
, uint_t proto
, uint_t flags
)
453 const char *ifname
= arg
;
457 /* if we are resetting, set the value to its default value */
458 if (flags
& IPADM_OPT_DEFAULT
)
459 pval
= IPADM_NONESTR
;
462 * cannot specify logical interface name. We can also filter out other
463 * bogus interface names here itself through i_ipadm_validate_ifname().
465 if (strcmp(pval
, IPADM_NONESTR
) != 0 &&
466 !i_ipadm_validate_ifname(iph
, pval
))
467 return (IPADM_INVALID_ARG
);
469 bzero(&lifr
, sizeof (lifr
));
470 (void) strlcpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
472 s
= (proto
== MOD_PROTO_IPV6
? iph
->iph_sock6
: iph
->iph_sock
);
474 if (strcmp(pval
, IPADM_NONESTR
) != 0) {
475 if ((ifindex
= if_nametoindex(pval
)) == 0)
476 return (ipadm_errno2status(errno
));
477 lifr
.lifr_index
= ifindex
;
479 if (ioctl(s
, SIOCGLIFUSESRC
, (caddr_t
)&lifr
) < 0)
480 return (ipadm_errno2status(errno
));
483 if (ioctl(s
, SIOCSLIFUSESRC
, (caddr_t
)&lifr
) < 0)
484 return (ipadm_errno2status(errno
));
486 return (IPADM_SUCCESS
);
489 static struct hostmodel_strval
{
491 ip_hostmodel_t esm_val
;
493 {"weak", IP_WEAK_ES
},
494 {"src-priority", IP_SRC_PRI_ES
},
495 {"strong", IP_STRONG_ES
},
496 {"custom", IP_MAXVAL_ES
}
499 static ip_hostmodel_t
500 i_ipadm_hostmodel_str2val(const char *pval
)
504 for (i
= 0; i
< A_CNT(esm_arr
); i
++) {
505 if (esm_arr
[i
].esm_str
!= NULL
&&
506 strcmp(pval
, esm_arr
[i
].esm_str
) == 0) {
507 return (esm_arr
[i
].esm_val
);
510 return (IP_MAXVAL_ES
);
514 i_ipadm_hostmodel_val2str(ip_hostmodel_t pval
)
518 for (i
= 0; i
< A_CNT(esm_arr
); i
++) {
519 if (esm_arr
[i
].esm_val
== pval
)
520 return (esm_arr
[i
].esm_str
);
526 static ipadm_status_t
527 i_ipadm_set_hostmodel(ipadm_handle_t iph
, const void *arg
,
528 ipadm_prop_desc_t
*pdp
, const void *pval
, uint_t proto
, uint_t flags
)
530 ip_hostmodel_t hostmodel
;
531 char val
[11]; /* covers uint32_max as a string */
533 if ((flags
& IPADM_OPT_DEFAULT
) == 0) {
534 hostmodel
= i_ipadm_hostmodel_str2val(pval
);
535 if (hostmodel
== IP_MAXVAL_ES
)
536 return (IPADM_INVALID_ARG
);
537 (void) snprintf(val
, sizeof (val
), "%d", hostmodel
);
540 return (i_ipadm_set_prop(iph
, NULL
, pdp
, pval
, proto
, flags
));
544 static ipadm_status_t
545 i_ipadm_get_hostmodel(ipadm_handle_t iph
, const void *arg
,
546 ipadm_prop_desc_t
*pdp
, char *buf
, uint_t
*bufsize
, uint_t proto
,
549 ip_hostmodel_t hostmodel
;
552 ipadm_status_t status
;
556 nbytes
= snprintf(buf
, *bufsize
, "%d", MOD_PROP_PERM_RW
);
558 case MOD_PROP_DEFAULT
:
559 nbytes
= snprintf(buf
, *bufsize
, "weak");
561 case MOD_PROP_ACTIVE
:
562 status
= i_ipadm_get_prop(iph
, arg
, pdp
, buf
, bufsize
, proto
,
564 if (status
!= IPADM_SUCCESS
)
566 bcopy(buf
, &hostmodel
, sizeof (hostmodel
));
567 cp
= i_ipadm_hostmodel_val2str(hostmodel
);
568 nbytes
= snprintf(buf
, *bufsize
, "%s",
569 (cp
!= NULL
? cp
: "?"));
571 case MOD_PROP_POSSIBLE
:
572 nbytes
= snprintf(buf
, *bufsize
, "strong,src-priority,weak");
575 return (IPADM_INVALID_ARG
);
577 if (nbytes
>= *bufsize
) {
578 /* insufficient buffer space */
579 *bufsize
= nbytes
+ 1;
580 return (IPADM_NO_BUFS
);
582 return (IPADM_SUCCESS
);
586 static ipadm_status_t
587 i_ipadm_set_ifprop_flags(ipadm_handle_t iph
, const void *arg
,
588 ipadm_prop_desc_t
*pdp
, const void *pval
, uint_t proto
, uint_t flags
)
590 ipadm_status_t status
= IPADM_SUCCESS
;
591 const char *ifname
= arg
;
592 uint64_t on_flags
= 0, off_flags
= 0;
593 boolean_t on
= B_FALSE
;
594 sa_family_t af
= (proto
== MOD_PROTO_IPV6
? AF_INET6
: AF_INET
);
596 /* if we are resetting, set the value to its default value */
597 if (flags
& IPADM_OPT_DEFAULT
) {
598 if (strcmp(pdp
->ipd_name
, "exchange_routes") == 0 ||
599 strcmp(pdp
->ipd_name
, "arp") == 0 ||
600 strcmp(pdp
->ipd_name
, "nud") == 0) {
602 } else if (strcmp(pdp
->ipd_name
, "forwarding") == 0) {
605 return (IPADM_PROP_UNKNOWN
);
609 if (strcmp(pval
, IPADM_ONSTR
) == 0)
611 else if (strcmp(pval
, IPADM_OFFSTR
) == 0)
614 return (IPADM_INVALID_ARG
);
616 if (strcmp(pdp
->ipd_name
, "exchange_routes") == 0) {
618 off_flags
= IFF_NORTEXCH
;
620 on_flags
= IFF_NORTEXCH
;
621 } else if (strcmp(pdp
->ipd_name
, "arp") == 0) {
623 off_flags
= IFF_NOARP
;
625 on_flags
= IFF_NOARP
;
626 } else if (strcmp(pdp
->ipd_name
, "nud") == 0) {
628 off_flags
= IFF_NONUD
;
630 on_flags
= IFF_NONUD
;
631 } else if (strcmp(pdp
->ipd_name
, "forwarding") == 0) {
633 on_flags
= IFF_ROUTER
;
635 off_flags
= IFF_ROUTER
;
638 if (on_flags
|| off_flags
) {
639 status
= i_ipadm_set_flags(iph
, ifname
, af
, on_flags
,
646 static ipadm_status_t
647 i_ipadm_set_eprivport(ipadm_handle_t iph
, const void *arg
,
648 ipadm_prop_desc_t
*pdp
, const void *pval
, uint_t proto
, uint_t flags
)
650 nvlist_t
*portsnvl
= NULL
;
652 ipadm_status_t status
= IPADM_SUCCESS
;
656 if (flags
& IPADM_OPT_DEFAULT
) {
657 assert(pval
== NULL
);
658 return (i_ipadm_set_prop(iph
, arg
, pdp
, pval
, proto
, flags
));
661 if ((err
= ipadm_str2nvlist(pval
, &portsnvl
, IPADM_NORVAL
)) != 0)
662 return (ipadm_errno2status(err
));
664 /* count the number of ports */
665 for (nvp
= nvlist_next_nvpair(portsnvl
, NULL
); nvp
!= NULL
;
666 nvp
= nvlist_next_nvpair(portsnvl
, nvp
)) {
670 if (iph
->iph_flags
& IPH_INIT
) {
671 flags
|= IPADM_OPT_APPEND
;
672 } else if (count
> 1) {
674 * We allow only one port to be added, removed or
675 * assigned at a time.
677 * However on reboot, while initializing protocol
678 * properties, extra_priv_ports might have multiple
679 * values. Only in that case we allow setting multiple
682 nvlist_free(portsnvl
);
683 return (IPADM_INVALID_ARG
);
686 for (nvp
= nvlist_next_nvpair(portsnvl
, NULL
); nvp
!= NULL
;
687 nvp
= nvlist_next_nvpair(portsnvl
, nvp
)) {
688 status
= i_ipadm_set_prop(iph
, arg
, pdp
, nvpair_name(nvp
),
690 if (status
!= IPADM_SUCCESS
)
693 nvlist_free(portsnvl
);
698 static ipadm_status_t
699 i_ipadm_set_forwarding(ipadm_handle_t iph
, const void *arg
,
700 ipadm_prop_desc_t
*pdp
, const void *pval
, uint_t proto
, uint_t flags
)
702 const char *ifname
= arg
;
703 ipadm_status_t status
;
706 * if interface name is provided, then set forwarding using the
709 if (ifname
!= NULL
) {
710 status
= i_ipadm_set_ifprop_flags(iph
, ifname
, pdp
, pval
,
716 * if the caller is IPH_LEGACY, `pval' already contains
719 if (!(flags
& IPADM_OPT_DEFAULT
) &&
720 !(iph
->iph_flags
& IPH_LEGACY
)) {
722 if (strcmp(pval
, IPADM_ONSTR
) == 0)
724 else if (strcmp(pval
, IPADM_OFFSTR
) == 0)
727 return (IPADM_INVALID_ARG
);
731 status
= i_ipadm_set_prop(iph
, ifname
, pdp
, pval
, proto
, flags
);
738 static ipadm_status_t
739 i_ipadm_set_ecnsack(ipadm_handle_t iph
, const void *arg
,
740 ipadm_prop_desc_t
*pdp
, const void *pval
, uint_t proto
, uint_t flags
)
743 char val
[MAXPROPVALLEN
];
745 /* if IPH_LEGACY is set, `pval' already contains numeric values */
746 if (!(flags
& IPADM_OPT_DEFAULT
) && !(iph
->iph_flags
& IPH_LEGACY
)) {
747 for (i
= 0; ecn_sack_vals
[i
] != NULL
; i
++) {
748 if (strcmp(pval
, ecn_sack_vals
[i
]) == 0)
751 if (ecn_sack_vals
[i
] == NULL
)
752 return (IPADM_INVALID_ARG
);
753 (void) snprintf(val
, MAXPROPVALLEN
, "%d", i
);
757 return (i_ipadm_set_prop(iph
, arg
, pdp
, pval
, proto
, flags
));
762 i_ipadm_get_ecnsack(ipadm_handle_t iph
, const void *arg
,
763 ipadm_prop_desc_t
*pdp
, char *buf
, uint_t
*bufsize
, uint_t proto
,
766 ipadm_status_t status
= IPADM_SUCCESS
;
767 uint_t i
, nbytes
= 0;
770 case MOD_PROP_POSSIBLE
:
771 for (i
= 0; ecn_sack_vals
[i
] != NULL
; i
++) {
773 nbytes
+= snprintf(buf
+ nbytes
,
774 *bufsize
- nbytes
, "%s", ecn_sack_vals
[i
]);
776 nbytes
+= snprintf(buf
+ nbytes
,
777 *bufsize
- nbytes
, ",%s", ecn_sack_vals
[i
]);
778 if (nbytes
>= *bufsize
)
783 case MOD_PROP_DEFAULT
:
784 case MOD_PROP_ACTIVE
:
785 status
= i_ipadm_get_prop(iph
, arg
, pdp
, buf
, bufsize
, proto
,
789 * If IPH_LEGACY is set, do not convert the value returned
792 if (iph
->iph_flags
& IPH_LEGACY
)
796 * For current and default value, convert the value returned
797 * from kernel to more discrete representation.
799 if (status
== IPADM_SUCCESS
&& (valtype
== MOD_PROP_ACTIVE
||
800 valtype
== MOD_PROP_DEFAULT
)) {
803 nbytes
= snprintf(buf
, *bufsize
, "%s",
808 return (IPADM_INVALID_ARG
);
810 if (nbytes
>= *bufsize
) {
811 /* insufficient buffer space */
812 *bufsize
= nbytes
+ 1;
813 return (IPADM_NO_BUFS
);
820 static ipadm_status_t
821 i_ipadm_get_forwarding(ipadm_handle_t iph
, const void *arg
,
822 ipadm_prop_desc_t
*pdp
, char *buf
, uint_t
*bufsize
, uint_t proto
,
825 const char *ifname
= arg
;
826 ipadm_status_t status
= IPADM_SUCCESS
;
829 * if interface name is provided, then get forwarding status using
832 if (ifname
!= NULL
) {
833 status
= i_ipadm_get_ifprop_flags(iph
, ifname
, pdp
,
834 buf
, bufsize
, pdp
->ipd_proto
, valtype
);
836 status
= i_ipadm_get_prop(iph
, ifname
, pdp
, buf
,
837 bufsize
, proto
, valtype
);
839 * If IPH_LEGACY is set, do not convert the value returned
842 if (iph
->iph_flags
& IPH_LEGACY
)
844 if (status
== IPADM_SUCCESS
&& (valtype
== MOD_PROP_ACTIVE
||
845 valtype
== MOD_PROP_DEFAULT
)) {
846 uint_t val
= atoi(buf
);
848 (void) snprintf(buf
, *bufsize
,
849 (val
== 1 ? IPADM_ONSTR
: IPADM_OFFSTR
));
858 static ipadm_status_t
859 i_ipadm_get_mtu(ipadm_handle_t iph
, const void *arg
,
860 ipadm_prop_desc_t
*pdp
, char *buf
, uint_t
*bufsize
, uint_t proto
,
864 const char *ifname
= arg
;
870 nbytes
= snprintf(buf
, *bufsize
, "%d", MOD_PROP_PERM_RW
);
872 case MOD_PROP_DEFAULT
:
873 case MOD_PROP_POSSIBLE
:
874 return (i_ipadm_get_prop(iph
, arg
, pdp
, buf
, bufsize
,
876 case MOD_PROP_ACTIVE
:
877 bzero(&lifr
, sizeof (lifr
));
878 (void) strlcpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
879 s
= (proto
== MOD_PROTO_IPV6
? iph
->iph_sock6
: iph
->iph_sock
);
881 if (ioctl(s
, SIOCGLIFMTU
, (caddr_t
)&lifr
) < 0)
882 return (ipadm_errno2status(errno
));
883 nbytes
= snprintf(buf
, *bufsize
, "%u", lifr
.lifr_mtu
);
886 return (IPADM_INVALID_ARG
);
888 if (nbytes
>= *bufsize
) {
889 /* insufficient buffer space */
890 *bufsize
= nbytes
+ 1;
891 return (IPADM_NO_BUFS
);
893 return (IPADM_SUCCESS
);
897 static ipadm_status_t
898 i_ipadm_get_metric(ipadm_handle_t iph
, const void *arg
,
899 ipadm_prop_desc_t
*pdp
, char *buf
, uint_t
*bufsize
, uint_t proto
,
903 const char *ifname
= arg
;
909 val
= MOD_PROP_PERM_RW
;
911 case MOD_PROP_DEFAULT
:
912 val
= DEF_METRIC_VAL
;
914 case MOD_PROP_ACTIVE
:
915 bzero(&lifr
, sizeof (lifr
));
916 (void) strlcpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
918 s
= (proto
== MOD_PROTO_IPV6
? iph
->iph_sock6
: iph
->iph_sock
);
919 if (ioctl(s
, SIOCGLIFMETRIC
, (caddr_t
)&lifr
) < 0)
920 return (ipadm_errno2status(errno
));
921 val
= lifr
.lifr_metric
;
924 return (IPADM_INVALID_ARG
);
926 nbytes
= snprintf(buf
, *bufsize
, "%d", val
);
927 if (nbytes
>= *bufsize
) {
928 /* insufficient buffer space */
929 *bufsize
= nbytes
+ 1;
930 return (IPADM_NO_BUFS
);
933 return (IPADM_SUCCESS
);
937 static ipadm_status_t
938 i_ipadm_get_usesrc(ipadm_handle_t iph
, const void *arg
,
939 ipadm_prop_desc_t
*ipd
, char *buf
, uint_t
*bufsize
, uint_t proto
,
943 const char *ifname
= arg
;
945 char if_name
[IF_NAMESIZE
];
950 nbytes
= snprintf(buf
, *bufsize
, "%d", MOD_PROP_PERM_RW
);
952 case MOD_PROP_DEFAULT
:
953 nbytes
= snprintf(buf
, *bufsize
, "%s", IPADM_NONESTR
);
955 case MOD_PROP_ACTIVE
:
956 bzero(&lifr
, sizeof (lifr
));
957 (void) strlcpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
959 s
= (proto
== MOD_PROTO_IPV6
? iph
->iph_sock6
: iph
->iph_sock
);
960 if (ioctl(s
, SIOCGLIFUSESRC
, (caddr_t
)&lifr
) < 0)
961 return (ipadm_errno2status(errno
));
962 if (lifr
.lifr_index
== 0) {
963 /* no src address was set, so print 'none' */
964 (void) strlcpy(if_name
, IPADM_NONESTR
,
966 } else if (if_indextoname(lifr
.lifr_index
, if_name
) == NULL
) {
967 return (ipadm_errno2status(errno
));
969 nbytes
= snprintf(buf
, *bufsize
, "%s", if_name
);
972 return (IPADM_INVALID_ARG
);
974 if (nbytes
>= *bufsize
) {
975 /* insufficient buffer space */
976 *bufsize
= nbytes
+ 1;
977 return (IPADM_NO_BUFS
);
979 return (IPADM_SUCCESS
);
983 static ipadm_status_t
984 i_ipadm_get_ifprop_flags(ipadm_handle_t iph
, const void *arg
,
985 ipadm_prop_desc_t
*pdp
, char *buf
, uint_t
*bufsize
, uint_t proto
,
991 const char *ifname
= arg
;
993 ipadm_status_t status
= IPADM_SUCCESS
;
997 nbytes
= snprintf(buf
, *bufsize
, "%d", MOD_PROP_PERM_RW
);
999 case MOD_PROP_DEFAULT
:
1000 if (strcmp(pdp
->ipd_name
, "exchange_routes") == 0 ||
1001 strcmp(pdp
->ipd_name
, "arp") == 0 ||
1002 strcmp(pdp
->ipd_name
, "nud") == 0) {
1004 } else if (strcmp(pdp
->ipd_name
, "forwarding") == 0) {
1007 return (IPADM_PROP_UNKNOWN
);
1009 nbytes
= snprintf(buf
, *bufsize
, "%s", val
);
1011 case MOD_PROP_ACTIVE
:
1012 af
= (proto
== MOD_PROTO_IPV6
? AF_INET6
: AF_INET
);
1013 status
= i_ipadm_get_flags(iph
, ifname
, af
, &intf_flags
);
1014 if (status
!= IPADM_SUCCESS
)
1018 if (strcmp(pdp
->ipd_name
, "exchange_routes") == 0) {
1019 if (!(intf_flags
& IFF_NORTEXCH
))
1021 } else if (strcmp(pdp
->ipd_name
, "forwarding") == 0) {
1022 if (intf_flags
& IFF_ROUTER
)
1024 } else if (strcmp(pdp
->ipd_name
, "arp") == 0) {
1025 if (!(intf_flags
& IFF_NOARP
))
1027 } else if (strcmp(pdp
->ipd_name
, "nud") == 0) {
1028 if (!(intf_flags
& IFF_NONUD
))
1031 nbytes
= snprintf(buf
, *bufsize
, "%s", val
);
1034 return (IPADM_INVALID_ARG
);
1036 if (nbytes
>= *bufsize
) {
1037 /* insufficient buffer space */
1038 *bufsize
= nbytes
+ 1;
1039 status
= IPADM_NO_BUFS
;
1046 i_ipadm_perm2str(char *buf
, uint_t
*bufsize
)
1048 uint_t perm
= atoi(buf
);
1050 (void) snprintf(buf
, *bufsize
, "%c%c",
1051 ((perm
& MOD_PROP_PERM_READ
) != 0) ? 'r' : '-',
1052 ((perm
& MOD_PROP_PERM_WRITE
) != 0) ? 'w' : '-');
1056 static ipadm_status_t
1057 i_ipadm_get_prop(ipadm_handle_t iph
, const void *arg
,
1058 ipadm_prop_desc_t
*pdp
, char *buf
, uint_t
*bufsize
, uint_t proto
,
1061 ipadm_status_t status
= IPADM_SUCCESS
;
1062 const char *ifname
= arg
;
1063 mod_ioc_prop_t
*mip
;
1064 char *pname
= pdp
->ipd_name
;
1067 /* allocate sufficient ioctl buffer to retrieve value */
1068 iocsize
= sizeof (mod_ioc_prop_t
);
1069 if ((mip
= calloc(1, iocsize
)) == NULL
)
1070 return (IPADM_NO_BUFS
);
1072 mip
->mpr_version
= MOD_PROP_VERSION
;
1073 mip
->mpr_flags
= valtype
;
1074 mip
->mpr_proto
= proto
;
1075 if (ifname
!= NULL
) {
1076 (void) strlcpy(mip
->mpr_ifname
, ifname
,
1077 sizeof (mip
->mpr_ifname
));
1079 (void) strlcpy(mip
->mpr_name
, pname
, sizeof (mip
->mpr_name
));
1081 if (ioctl(iph
->iph_sock
, SIOCGETPROP
, (char *)mip
) < 0) {
1082 if (errno
== ENOENT
)
1083 status
= IPADM_PROP_UNKNOWN
;
1085 status
= ipadm_errno2status(errno
);
1087 bcopy(mip
->mpr_val
, buf
, *bufsize
);
1095 * Populates the ipmgmt_prop_arg_t based on the class of property.
1097 * For private protocol properties, while persisting information in ipadm
1098 * data store, to ensure there is no collision of namespace between ipadm
1099 * private nvpair names (which also starts with '_', see ipadm_ipmgmt.h)
1100 * and private protocol property names, we will prepend IPADM_PRIV_PROP_PREFIX
1101 * to property names.
1104 i_ipadm_populate_proparg(ipmgmt_prop_arg_t
*pargp
, ipadm_prop_desc_t
*pdp
,
1105 const char *pval
, const void *object
)
1107 const struct ipadm_addrobj_s
*ipaddr
;
1108 uint_t
class = pdp
->ipd_class
;
1109 uint_t proto
= pdp
->ipd_proto
;
1111 (void) strlcpy(pargp
->ia_pname
, pdp
->ipd_name
,
1112 sizeof (pargp
->ia_pname
));
1114 (void) strlcpy(pargp
->ia_pval
, pval
, sizeof (pargp
->ia_pval
));
1117 case IPADMPROP_CLASS_MODULE
:
1118 /* if it's a private property then add the prefix. */
1119 if (pdp
->ipd_name
[0] == '_') {
1120 (void) snprintf(pargp
->ia_pname
,
1121 sizeof (pargp
->ia_pname
), "_%s", pdp
->ipd_name
);
1123 (void) strlcpy(pargp
->ia_module
, object
,
1124 sizeof (pargp
->ia_module
));
1126 case IPADMPROP_CLASS_MODIF
:
1127 /* check if object is protostr or an ifname */
1128 if (ipadm_str2proto(object
) != MOD_PROTO_NONE
) {
1129 (void) strlcpy(pargp
->ia_module
, object
,
1130 sizeof (pargp
->ia_module
));
1133 /* it's an interface property, fall through */
1135 case IPADMPROP_CLASS_IF
:
1136 (void) strlcpy(pargp
->ia_ifname
, object
,
1137 sizeof (pargp
->ia_ifname
));
1138 (void) strlcpy(pargp
->ia_module
, ipadm_proto2str(proto
),
1139 sizeof (pargp
->ia_module
));
1141 case IPADMPROP_CLASS_ADDR
:
1143 (void) strlcpy(pargp
->ia_ifname
, ipaddr
->ipadm_ifname
,
1144 sizeof (pargp
->ia_ifname
));
1145 (void) strlcpy(pargp
->ia_aobjname
, ipaddr
->ipadm_aobjname
,
1146 sizeof (pargp
->ia_aobjname
));
1152 * Common function to retrieve property value for a given interface `ifname' or
1153 * for a given protocol `proto'. The property name is in `pname'.
1155 * `valtype' determines the type of value that will be retrieved.
1156 * IPADM_OPT_ACTIVE - current value of the property (active config)
1157 * IPADM_OPT_PERSIST - value of the property from persistent store
1158 * IPADM_OPT_DEFAULT - default hard coded value (boot-time value)
1159 * IPADM_OPT_PERM - read/write permissions for the value
1160 * IPADM_OPT_POSSIBLE - range of values
1162 static ipadm_status_t
1163 i_ipadm_getprop_common(ipadm_handle_t iph
, const char *ifname
,
1164 const char *pname
, char *buf
, uint_t
*bufsize
, uint_t proto
,
1167 ipadm_status_t status
= IPADM_SUCCESS
;
1168 ipadm_prop_desc_t
*pdp
;
1169 char priv_propname
[MAXPROPNAMELEN
];
1170 boolean_t is_if
= (ifname
!= NULL
);
1173 pdp
= i_ipadm_get_prop_desc(pname
, proto
, &err
);
1175 return (IPADM_BAD_PROTOCOL
);
1176 /* there are no private interface properties */
1177 if (is_if
&& err
== ENOENT
)
1178 return (IPADM_PROP_UNKNOWN
);
1182 * check whether the property can be
1183 * applied on an interface
1185 if (is_if
&& !(pdp
->ipd_class
& IPADMPROP_CLASS_IF
))
1186 return (IPADM_INVALID_ARG
);
1188 * check whether the property can be
1189 * applied on a module
1191 if (!is_if
&& !(pdp
->ipd_class
& IPADMPROP_CLASS_MODULE
))
1192 return (IPADM_INVALID_ARG
);
1195 /* private protocol properties, pass it to kernel directly */
1196 pdp
= &ipadm_privprop
;
1197 (void) strlcpy(priv_propname
, pname
, sizeof (priv_propname
));
1198 pdp
->ipd_name
= priv_propname
;
1202 case IPADM_OPT_PERM
:
1203 status
= pdp
->ipd_get(iph
, ifname
, pdp
, buf
, bufsize
, proto
,
1205 if (status
== IPADM_SUCCESS
)
1206 i_ipadm_perm2str(buf
, bufsize
);
1208 case IPADM_OPT_ACTIVE
:
1209 status
= pdp
->ipd_get(iph
, ifname
, pdp
, buf
, bufsize
, proto
,
1212 case IPADM_OPT_DEFAULT
:
1213 status
= pdp
->ipd_get(iph
, ifname
, pdp
, buf
, bufsize
, proto
,
1216 case IPADM_OPT_POSSIBLE
:
1217 if (pdp
->ipd_get_range
!= NULL
) {
1218 status
= pdp
->ipd_get_range(iph
, ifname
, pdp
, buf
,
1219 bufsize
, proto
, MOD_PROP_POSSIBLE
);
1224 case IPADM_OPT_PERSIST
:
1225 /* retrieve from database */
1227 status
= i_ipadm_get_persist_propval(iph
, pdp
, buf
,
1230 status
= i_ipadm_get_persist_propval(iph
, pdp
, buf
,
1231 bufsize
, ipadm_proto2str(proto
));
1234 status
= IPADM_INVALID_ARG
;
1241 * Get protocol property of the specified protocol.
1244 ipadm_get_prop(ipadm_handle_t iph
, const char *pname
, char *buf
,
1245 uint_t
*bufsize
, uint_t proto
, uint_t valtype
)
1248 * validate the arguments of the function.
1250 if (iph
== NULL
|| pname
== NULL
|| buf
== NULL
||
1251 bufsize
== NULL
|| *bufsize
== 0) {
1252 return (IPADM_INVALID_ARG
);
1255 * Do we support this proto, if not return error.
1257 if (ipadm_proto2str(proto
) == NULL
)
1258 return (IPADM_NOTSUP
);
1260 return (i_ipadm_getprop_common(iph
, NULL
, pname
, buf
, bufsize
,
1265 * Get interface property of the specified interface.
1268 ipadm_get_ifprop(ipadm_handle_t iph
, const char *ifname
, const char *pname
,
1269 char *buf
, uint_t
*bufsize
, uint_t proto
, uint_t valtype
)
1271 /* validate the arguments of the function. */
1272 if (iph
== NULL
|| pname
== NULL
|| buf
== NULL
||
1273 bufsize
== NULL
|| *bufsize
== 0) {
1274 return (IPADM_INVALID_ARG
);
1277 /* Do we support this proto, if not return error. */
1278 if (ipadm_proto2str(proto
) == NULL
)
1279 return (IPADM_NOTSUP
);
1282 * check if interface name is provided for interface property and
1285 if (!i_ipadm_validate_ifname(iph
, ifname
))
1286 return (IPADM_INVALID_ARG
);
1288 return (i_ipadm_getprop_common(iph
, ifname
, pname
, buf
, bufsize
,
1293 * Allocates sufficient ioctl buffers and copies property name and the
1294 * value, among other things. If the flag IPADM_OPT_DEFAULT is set, then
1295 * `pval' will be NULL and it instructs the kernel to reset the current
1296 * value to property's default value.
1298 static ipadm_status_t
1299 i_ipadm_set_prop(ipadm_handle_t iph
, const void *arg
,
1300 ipadm_prop_desc_t
*pdp
, const void *pval
, uint_t proto
, uint_t flags
)
1302 ipadm_status_t status
= IPADM_SUCCESS
;
1303 const char *ifname
= arg
;
1304 mod_ioc_prop_t
*mip
;
1305 char *pname
= pdp
->ipd_name
;
1307 uint_t iocflags
= 0;
1309 if (flags
& IPADM_OPT_DEFAULT
) {
1310 iocflags
|= MOD_PROP_DEFAULT
;
1311 } else if (flags
& IPADM_OPT_ACTIVE
) {
1312 iocflags
|= MOD_PROP_ACTIVE
;
1313 if (flags
& IPADM_OPT_APPEND
)
1314 iocflags
|= MOD_PROP_APPEND
;
1315 else if (flags
& IPADM_OPT_REMOVE
)
1316 iocflags
|= MOD_PROP_REMOVE
;
1319 iocsize
= sizeof (mod_ioc_prop_t
);
1321 if ((mip
= calloc(1, iocsize
)) == NULL
)
1322 return (IPADM_NO_BUFS
);
1324 mip
->mpr_version
= MOD_PROP_VERSION
;
1325 mip
->mpr_flags
= iocflags
;
1326 mip
->mpr_proto
= proto
;
1327 if (ifname
!= NULL
) {
1328 (void) strlcpy(mip
->mpr_ifname
, ifname
,
1329 sizeof (mip
->mpr_ifname
));
1332 (void) strlcpy(mip
->mpr_name
, pname
, sizeof (mip
->mpr_name
));
1334 (void) strlcpy(mip
->mpr_val
, pval
, sizeof(mip
->mpr_val
));
1336 if (ioctl(iph
->iph_sock
, SIOCSETPROP
, (char *)mip
) < 0) {
1337 if (errno
== ENOENT
)
1338 status
= IPADM_PROP_UNKNOWN
;
1340 status
= ipadm_errno2status(errno
);
1347 * Common function for modifying both protocol/interface property.
1350 * IPADM_OPT_PERSIST is set then the value is persisted.
1351 * IPADM_OPT_DEFAULT is set then the default value for the property will
1354 static ipadm_status_t
1355 i_ipadm_setprop_common(ipadm_handle_t iph
, const char *ifname
,
1356 const char *pname
, const char *buf
, uint_t proto
, uint_t pflags
)
1358 ipadm_status_t status
= IPADM_SUCCESS
;
1359 boolean_t persist
= (pflags
& IPADM_OPT_PERSIST
);
1360 boolean_t reset
= (pflags
& IPADM_OPT_DEFAULT
);
1361 ipadm_prop_desc_t
*pdp
;
1362 boolean_t is_if
= (ifname
!= NULL
);
1363 char priv_propname
[MAXPROPNAMELEN
];
1366 /* Check that property value is within the allowed size */
1367 if (!reset
&& strnlen(buf
, MAXPROPVALLEN
) >= MAXPROPVALLEN
)
1368 return (IPADM_INVALID_ARG
);
1370 pdp
= i_ipadm_get_prop_desc(pname
, proto
, &err
);
1372 return (IPADM_BAD_PROTOCOL
);
1373 /* there are no private interface properties */
1374 if (is_if
&& err
== ENOENT
)
1375 return (IPADM_PROP_UNKNOWN
);
1378 /* do some sanity checks */
1380 if (!(pdp
->ipd_class
& IPADMPROP_CLASS_IF
))
1381 return (IPADM_INVALID_ARG
);
1383 if (!(pdp
->ipd_class
& IPADMPROP_CLASS_MODULE
))
1384 return (IPADM_INVALID_ARG
);
1387 * if the property is not multi-valued and IPADM_OPT_APPEND or
1388 * IPADM_OPT_REMOVE is specified, return IPADM_INVALID_ARG.
1390 if (!(pdp
->ipd_flags
& IPADMPROP_MULVAL
) && (pflags
&
1391 (IPADM_OPT_APPEND
|IPADM_OPT_REMOVE
))) {
1392 return (IPADM_INVALID_ARG
);
1395 /* private protocol property, pass it to kernel directly */
1396 pdp
= &ipadm_privprop
;
1397 (void) strlcpy(priv_propname
, pname
, sizeof (priv_propname
));
1398 pdp
->ipd_name
= priv_propname
;
1401 status
= pdp
->ipd_set(iph
, ifname
, pdp
, buf
, proto
, pflags
);
1402 if (status
!= IPADM_SUCCESS
)
1407 status
= i_ipadm_persist_propval(iph
, pdp
, buf
, ifname
,
1410 status
= i_ipadm_persist_propval(iph
, pdp
, buf
,
1411 ipadm_proto2str(proto
), pflags
);
1417 * Sets the property value of the specified interface
1420 ipadm_set_ifprop(ipadm_handle_t iph
, const char *ifname
, const char *pname
,
1421 const char *buf
, uint_t proto
, uint_t pflags
)
1423 boolean_t reset
= (pflags
& IPADM_OPT_DEFAULT
);
1424 ipadm_status_t status
;
1426 /* check for solaris.network.interface.config authorization */
1427 if (!ipadm_check_auth())
1428 return (IPADM_EAUTH
);
1430 * validate the arguments of the function.
1432 if (iph
== NULL
|| pname
== NULL
|| (!reset
&& buf
== NULL
) ||
1433 pflags
== 0 || pflags
== IPADM_OPT_PERSIST
||
1434 (pflags
& ~(IPADM_COMMON_OPT_MASK
|IPADM_OPT_DEFAULT
))) {
1435 return (IPADM_INVALID_ARG
);
1439 * Do we support this protocol, if not return error.
1441 if (ipadm_proto2str(proto
) == NULL
)
1442 return (IPADM_NOTSUP
);
1445 * Validate the interface and check if a persistent
1446 * operation is performed on a temporary object.
1448 status
= i_ipadm_validate_if(iph
, ifname
, proto
, pflags
);
1449 if (status
!= IPADM_SUCCESS
)
1452 return (i_ipadm_setprop_common(iph
, ifname
, pname
, buf
, proto
,
1457 * Sets the property value of the specified protocol.
1460 ipadm_set_prop(ipadm_handle_t iph
, const char *pname
, const char *buf
,
1461 uint_t proto
, uint_t pflags
)
1463 boolean_t reset
= (pflags
& IPADM_OPT_DEFAULT
);
1465 /* check for solaris.network.interface.config authorization */
1466 if (!ipadm_check_auth())
1467 return (IPADM_EAUTH
);
1469 * validate the arguments of the function.
1471 if (iph
== NULL
|| pname
== NULL
||(!reset
&& buf
== NULL
) ||
1472 pflags
== 0 || pflags
== IPADM_OPT_PERSIST
||
1473 (pflags
& ~(IPADM_COMMON_OPT_MASK
|IPADM_OPT_DEFAULT
|
1474 IPADM_OPT_APPEND
|IPADM_OPT_REMOVE
))) {
1475 return (IPADM_INVALID_ARG
);
1479 * Do we support this proto, if not return error.
1481 if (ipadm_proto2str(proto
) == NULL
)
1482 return (IPADM_NOTSUP
);
1484 return (i_ipadm_setprop_common(iph
, NULL
, pname
, buf
, proto
,
1488 /* helper function for ipadm_walk_proptbl */
1490 i_ipadm_walk_proptbl(ipadm_prop_desc_t
*pdtbl
, uint_t proto
, uint_t
class,
1491 ipadm_prop_wfunc_t
*func
, void *arg
)
1493 ipadm_prop_desc_t
*pdp
;
1495 for (pdp
= pdtbl
; pdp
->ipd_name
!= NULL
; pdp
++) {
1496 if (!(pdp
->ipd_class
& class))
1499 if (proto
!= MOD_PROTO_NONE
&& !(pdp
->ipd_proto
& proto
))
1503 * we found a class specific match, call the
1504 * user callback function.
1506 if (func(arg
, pdp
->ipd_name
, pdp
->ipd_proto
) == B_FALSE
)
1512 * Walks through all the properties, for a given protocol and property class
1513 * (protocol or interface).
1515 * Further if proto == MOD_PROTO_NONE, then it walks through all the supported
1516 * protocol property tables.
1519 ipadm_walk_proptbl(uint_t proto
, uint_t
class, ipadm_prop_wfunc_t
*func
,
1522 ipadm_prop_desc_t
*pdtbl
;
1523 ipadm_status_t status
= IPADM_SUCCESS
;
1525 int count
= A_CNT(protocols
);
1528 return (IPADM_INVALID_ARG
);
1531 case IPADMPROP_CLASS_ADDR
:
1532 pdtbl
= ipadm_addrprop_table
;
1534 case IPADMPROP_CLASS_IF
:
1535 case IPADMPROP_CLASS_MODULE
:
1536 pdtbl
= i_ipadm_get_propdesc_table(proto
);
1537 if (pdtbl
== NULL
&& proto
!= MOD_PROTO_NONE
)
1538 return (IPADM_INVALID_ARG
);
1541 return (IPADM_INVALID_ARG
);
1544 if (pdtbl
!= NULL
) {
1546 * proto will be MOD_PROTO_NONE in the case of
1547 * IPADMPROP_CLASS_ADDR.
1549 i_ipadm_walk_proptbl(pdtbl
, proto
, class, func
, arg
);
1551 /* Walk thru all the protocol tables, we support */
1552 for (i
= 0; i
< count
; i
++) {
1553 pdtbl
= i_ipadm_get_propdesc_table(protocols
[i
]);
1554 i_ipadm_walk_proptbl(pdtbl
, protocols
[i
], class, func
,
1562 * Given a property name, walks through all the instances of a property name.
1563 * Some properties have two instances one for v4 interfaces and another for v6
1564 * interfaces. For example: MTU. MTU can have different values for v4 and v6.
1565 * Therefore there are two properties for 'MTU'.
1567 * This function invokes `func' for every instance of property `pname'
1570 ipadm_walk_prop(const char *pname
, uint_t proto
, uint_t
class,
1571 ipadm_prop_wfunc_t
*func
, void *arg
)
1573 ipadm_prop_desc_t
*pdtbl
, *pdp
;
1574 ipadm_status_t status
= IPADM_SUCCESS
;
1575 boolean_t matched
= B_FALSE
;
1577 if (pname
== NULL
|| func
== NULL
)
1578 return (IPADM_INVALID_ARG
);
1581 case IPADMPROP_CLASS_ADDR
:
1582 pdtbl
= ipadm_addrprop_table
;
1584 case IPADMPROP_CLASS_IF
:
1585 case IPADMPROP_CLASS_MODULE
:
1586 pdtbl
= i_ipadm_get_propdesc_table(proto
);
1589 return (IPADM_INVALID_ARG
);
1593 return (IPADM_INVALID_ARG
);
1595 for (pdp
= pdtbl
; pdp
->ipd_name
!= NULL
; pdp
++) {
1596 if (strcmp(pname
, pdp
->ipd_name
) != 0)
1598 if (!(pdp
->ipd_proto
& proto
))
1601 /* we found a match, call the callback function */
1602 if (func(arg
, pdp
->ipd_name
, pdp
->ipd_proto
) == B_FALSE
)
1606 status
= IPADM_PROP_UNKNOWN
;
1612 i_ipadm_get_onoff(ipadm_handle_t iph
, const void *arg
, ipadm_prop_desc_t
*dp
,
1613 char *buf
, uint_t
*bufsize
, uint_t proto
, uint_t valtype
)
1615 (void) snprintf(buf
, *bufsize
, "%s,%s", IPADM_ONSTR
, IPADM_OFFSTR
);
1616 return (IPADM_SUCCESS
);
1620 * Makes a door call to ipmgmtd to retrieve the persisted property value
1623 i_ipadm_get_persist_propval(ipadm_handle_t iph
, ipadm_prop_desc_t
*pdp
,
1624 char *gbuf
, uint_t
*gbufsize
, const void *object
)
1626 ipmgmt_prop_arg_t parg
;
1627 ipmgmt_getprop_rval_t rval
, *rvalp
;
1631 bzero(&parg
, sizeof (parg
));
1632 parg
.ia_cmd
= IPMGMT_CMD_GETPROP
;
1633 i_ipadm_populate_proparg(&parg
, pdp
, NULL
, object
);
1636 err
= ipadm_door_call(iph
, &parg
, sizeof (parg
), (void **)&rvalp
,
1637 sizeof (rval
), B_FALSE
);
1639 /* assert that rvalp was not reallocated */
1640 assert(rvalp
== &rval
);
1642 /* `ir_pval' contains the property value */
1643 nbytes
= snprintf(gbuf
, *gbufsize
, "%s", rvalp
->ir_pval
);
1644 if (nbytes
>= *gbufsize
) {
1645 /* insufficient buffer space */
1646 *gbufsize
= nbytes
+ 1;
1650 return (ipadm_errno2status(err
));
1654 * Persists the property value for a given property in the data store
1657 i_ipadm_persist_propval(ipadm_handle_t iph
, ipadm_prop_desc_t
*pdp
,
1658 const char *pval
, const void *object
, uint_t flags
)
1660 ipmgmt_prop_arg_t parg
;
1663 bzero(&parg
, sizeof (parg
));
1664 i_ipadm_populate_proparg(&parg
, pdp
, pval
, object
);
1666 * Check if value to be persisted need to be appended or removed. This
1667 * is required for multi-valued property.
1669 if (flags
& IPADM_OPT_APPEND
)
1670 parg
.ia_flags
|= IPMGMT_APPEND
;
1671 if (flags
& IPADM_OPT_REMOVE
)
1672 parg
.ia_flags
|= IPMGMT_REMOVE
;
1674 if (flags
& (IPADM_OPT_DEFAULT
|IPADM_OPT_REMOVE
))
1675 parg
.ia_cmd
= IPMGMT_CMD_RESETPROP
;
1677 parg
.ia_cmd
= IPMGMT_CMD_SETPROP
;
1679 err
= ipadm_door_call(iph
, &parg
, sizeof (parg
), NULL
, 0, B_FALSE
);
1682 * its fine if there were no entry in the DB to delete. The user
1683 * might be changing property value, which was not changed
1688 return (ipadm_errno2status(err
));
1692 * This is called from ipadm_set_ifprop() to validate the set operation.
1693 * It does the following steps:
1694 * 1. Validates the interface name.
1695 * 2. Fails if it is an IPMP meta-interface or an underlying interface.
1696 * 3. In case of a persistent operation, verifies that the
1697 * interface is persistent.
1699 static ipadm_status_t
1700 i_ipadm_validate_if(ipadm_handle_t iph
, const char *ifname
,
1701 uint_t proto
, uint_t flags
)
1703 sa_family_t af
, other_af
;
1704 ipadm_status_t status
;
1706 boolean_t af_exists
, other_af_exists
, a_exists
;
1708 /* Check if the interface name is valid. */
1709 if (!i_ipadm_validate_ifname(iph
, ifname
))
1710 return (IPADM_INVALID_ARG
);
1712 af
= (proto
== MOD_PROTO_IPV6
? AF_INET6
: AF_INET
);
1714 * Setting properties on an IPMP meta-interface or underlying
1715 * interface is not supported.
1717 if (i_ipadm_is_ipmp(iph
, ifname
) || i_ipadm_is_under_ipmp(iph
, ifname
))
1718 return (IPADM_NOTSUP
);
1720 /* Check if interface exists in the persistent configuration. */
1721 status
= i_ipadm_if_pexists(iph
, ifname
, af
, &p_exists
);
1722 if (status
!= IPADM_SUCCESS
)
1725 /* Check if interface exists in the active configuration. */
1726 af_exists
= ipadm_if_enabled(iph
, ifname
, af
);
1727 other_af
= (af
== AF_INET
? AF_INET6
: AF_INET
);
1728 other_af_exists
= ipadm_if_enabled(iph
, ifname
, other_af
);
1729 a_exists
= (af_exists
|| other_af_exists
);
1730 if (!a_exists
&& p_exists
)
1731 return (IPADM_OP_DISABLE_OBJ
);
1733 return (IPADM_ENXIO
);
1736 * If a persistent operation is requested, check if the underlying
1737 * IP interface is persistent.
1739 if ((flags
& IPADM_OPT_PERSIST
) && !p_exists
)
1740 return (IPADM_TEMPORARY_OBJ
);
1741 return (IPADM_SUCCESS
);
1745 * Private protocol properties namespace scheme:
1747 * PSARC 2010/080 identified the private protocol property names to be the
1748 * leading protocol names. For e.g. tcp_strong_iss, ip_strict_src_multihoming,
1749 * et al,. However to be consistent with private data-link property names,
1750 * which starts with '_', private protocol property names will start with '_'.
1751 * For e.g. _strong_iss, _strict_src_multihoming, et al,.
1754 /* maps new private protocol property name to the old private property name */
1755 typedef struct ipadm_oname2nname_map
{
1759 } ipadm_oname2nname_map_t
;
1762 * IP is a special case. It isn't straight forward to derive the legacy name
1763 * from the new name and vice versa. No set standard was followed in naming
1764 * the properties and hence we need a table to capture the mapping.
1766 static ipadm_oname2nname_map_t name_map
[] = {
1767 { "arp_probe_delay", "_arp_probe_delay",
1769 { "arp_fastprobe_delay", "_arp_fastprobe_delay",
1771 { "arp_probe_interval", "_arp_probe_interval",
1773 { "arp_fastprobe_interval", "_arp_fastprobe_interval",
1775 { "arp_probe_count", "_arp_probe_count",
1777 { "arp_fastprobe_count", "_arp_fastprobe_count",
1779 { "arp_defend_interval", "_arp_defend_interval",
1781 { "arp_defend_rate", "_arp_defend_rate",
1783 { "arp_defend_period", "_arp_defend_period",
1785 { "ndp_defend_interval", "_ndp_defend_interval",
1787 { "ndp_defend_rate", "_ndp_defend_rate",
1789 { "ndp_defend_period", "_ndp_defend_period",
1791 { "igmp_max_version", "_igmp_max_version",
1793 { "mld_max_version", "_mld_max_version",
1795 { "ipsec_override_persocket_policy", "_ipsec_override_persocket_policy",
1797 { "ipsec_policy_log_interval", "_ipsec_policy_log_interval",
1799 { "icmp_accept_clear_messages", "_icmp_accept_clear_messages",
1801 { "igmp_accept_clear_messages", "_igmp_accept_clear_messages",
1803 { "pim_accept_clear_messages", "_pim_accept_clear_messages",
1805 { "ip_respond_to_echo_multicast", "_respond_to_echo_multicast",
1807 { "ip_send_redirects", "_send_redirects",
1809 { "ip_forward_src_routed", "_forward_src_routed",
1811 { "ip_icmp_return_data_bytes", "_icmp_return_data_bytes",
1813 { "ip_ignore_redirect", "_ignore_redirect",
1815 { "ip_strict_dst_multihoming", "_strict_dst_multihoming",
1817 { "ip_reasm_timeout", "_reasm_timeout",
1819 { "ip_strict_src_multihoming", "_strict_src_multihoming",
1821 { "ipv4_dad_announce_interval", "_dad_announce_interval",
1823 { "ipv4_icmp_return_pmtu", "_icmp_return_pmtu",
1825 { "ipv6_dad_announce_interval", "_dad_announce_interval",
1827 { "ipv6_icmp_return_pmtu", "_icmp_return_pmtu",
1829 { NULL
, NULL
, MOD_PROTO_NONE
}
1833 * Following API returns a new property name in `nname' for the given legacy
1834 * property name in `oname'.
1837 ipadm_legacy2new_propname(const char *oname
, char *nname
, uint_t nnamelen
,
1841 ipadm_oname2nname_map_t
*ionmp
;
1843 /* if it's a public property, there is nothing to return */
1844 if (i_ipadm_get_prop_desc(oname
, *proto
, NULL
) != NULL
)
1848 * we didn't find the `oname' in the table, check if the property
1849 * name begins with a leading protocol.
1854 if (strstr(oname
, "tcp_") == oname
)
1855 str
+= strlen("tcp");
1857 case MOD_PROTO_SCTP
:
1858 if (strstr(oname
, "sctp_") == oname
)
1859 str
+= strlen("sctp");
1862 if (strstr(oname
, "udp_") == oname
)
1863 str
+= strlen("udp");
1865 case MOD_PROTO_RAWIP
:
1866 if (strstr(oname
, "icmp_") == oname
)
1867 str
+= strlen("icmp");
1870 case MOD_PROTO_IPV4
:
1871 case MOD_PROTO_IPV6
:
1872 if (strstr(oname
, "ip6_") == oname
) {
1873 *proto
= MOD_PROTO_IPV6
;
1874 str
+= strlen("ip6");
1876 for (ionmp
= name_map
; ionmp
->iom_oname
!= NULL
;
1878 if (strcmp(oname
, ionmp
->iom_oname
) == 0) {
1879 str
= ionmp
->iom_nname
;
1880 *proto
= ionmp
->iom_proto
;
1884 if (ionmp
->iom_oname
!= NULL
)
1887 if (strstr(oname
, "ip_") == oname
) {
1888 *proto
= MOD_PROTO_IP
;
1889 str
+= strlen("ip");
1896 (void) snprintf(nname
, nnamelen
, "%s", str
);