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]
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2016 Argo Technologie SA.
25 * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
29 * Contains DB walker functions, which are of type `db_wfunc_t';
31 * typedef boolean_t db_wfunc_t(void *cbarg, nvlist_t *db_nvl, char *buf,
32 * size_t bufsize, int *errp);
34 * ipadm_rw_db() walks through the data store, one line at a time and calls
35 * these call back functions with:
36 * `cbarg' - callback argument
37 * `db_nvl' - representing a line from DB in nvlist_t form
38 * `buf' - character buffer to hold modified line
39 * `bufsize'- size of the buffer
40 * `errp' - captures any error inside the walker function.
42 * All the 'write' callback functions modify `db_nvl' based on `cbarg' and
43 * copy string representation of `db_nvl' (using ipadm_nvlist2str()) into `buf'.
44 * To delete a line from the DB, buf[0] is set to `\0'. Inside ipadm_rw_db(),
45 * the modified `buf' is written back into DB.
47 * All the 'read' callback functions, retrieve the information from the DB, by
48 * reading `db_nvl' and then populate the `cbarg'.
55 #include <sys/types.h>
56 #include <sys/socket.h>
57 #include <netinet/in.h>
58 #include <arpa/inet.h>
60 #include "ipmgmt_impl.h"
62 /* SCF related property group names and property names */
63 #define IPMGMTD_APP_PG "ipmgmtd"
64 #define IPMGMTD_PROP_FBD "first_boot_done"
65 #define IPMGMTD_PROP_DBVER "datastore_version"
66 #define IPMGMTD_TRUESTR "true"
68 #define ATYPE "_atype" /* name of the address type nvpair */
69 #define FLAGS "_flags" /* name of the flags nvpair */
72 * flag used by ipmgmt_persist_aobjmap() to indicate address type is
73 * IPADM_ADDR_IPV6_ADDRCONF.
75 #define IPMGMT_ATYPE_V6ACONF 0x1
77 extern pthread_rwlock_t ipmgmt_dbconf_lock
;
79 /* signifies whether volatile copy of data store is in use */
80 static boolean_t ipmgmt_rdonly_root
= B_FALSE
;
83 * Checks if the database nvl, `db_nvl' contains and matches ALL of the passed
84 * in private nvpairs `proto', `ifname' & `aobjname'.
87 ipmgmt_nvlist_match(nvlist_t
*db_nvl
, const char *proto
, const char *ifname
,
90 char *db_proto
= NULL
, *db_ifname
= NULL
;
91 char *db_aobjname
= NULL
;
95 /* walk through db_nvl and retrieve all its private nvpairs */
96 for (nvp
= nvlist_next_nvpair(db_nvl
, NULL
); nvp
!= NULL
;
97 nvp
= nvlist_next_nvpair(db_nvl
, nvp
)) {
98 name
= nvpair_name(nvp
);
99 if (strcmp(IPADM_NVP_PROTONAME
, name
) == 0)
100 (void) nvpair_value_string(nvp
, &db_proto
);
101 else if (strcmp(IPADM_NVP_IFNAME
, name
) == 0)
102 (void) nvpair_value_string(nvp
, &db_ifname
);
103 else if (strcmp(IPADM_NVP_AOBJNAME
, name
) == 0)
104 (void) nvpair_value_string(nvp
, &db_aobjname
);
107 if (proto
!= NULL
&& proto
[0] == '\0')
109 if (ifname
!= NULL
&& ifname
[0] == '\0')
111 if (aobjname
!= NULL
&& aobjname
[0] == '\0')
114 if ((proto
== NULL
&& db_proto
!= NULL
) ||
115 (proto
!= NULL
&& db_proto
== NULL
) ||
116 (proto
!= NULL
&& db_proto
!= NULL
&&
117 strcmp(proto
, db_proto
) != 0)) {
118 /* no intersection - different protocols. */
121 if ((ifname
== NULL
&& db_ifname
!= NULL
) ||
122 (ifname
!= NULL
&& db_ifname
== NULL
) ||
123 (ifname
!= NULL
&& db_ifname
!= NULL
&&
124 strcmp(ifname
, db_ifname
) != 0)) {
125 /* no intersection - different interfaces. */
128 if ((aobjname
== NULL
&& db_aobjname
!= NULL
) ||
129 (aobjname
!= NULL
&& db_aobjname
== NULL
) ||
130 (aobjname
!= NULL
&& db_aobjname
!= NULL
&&
131 strcmp(aobjname
, db_aobjname
) != 0)) {
132 /* no intersection - different address objects */
140 * Checks if the database nvl, `db_nvl' and the input nvl, `in_nvl' intersects.
143 ipmgmt_nvlist_intersects(nvlist_t
*db_nvl
, nvlist_t
*in_nvl
)
147 char *proto
= NULL
, *ifname
= NULL
, *aobjname
= NULL
;
149 /* walk through in_nvl and retrieve all its private nvpairs */
150 for (nvp
= nvlist_next_nvpair(in_nvl
, NULL
); nvp
!= NULL
;
151 nvp
= nvlist_next_nvpair(in_nvl
, nvp
)) {
152 name
= nvpair_name(nvp
);
153 if (strcmp(IPADM_NVP_PROTONAME
, name
) == 0)
154 (void) nvpair_value_string(nvp
, &proto
);
155 else if (strcmp(IPADM_NVP_IFNAME
, name
) == 0)
156 (void) nvpair_value_string(nvp
, &ifname
);
157 else if (strcmp(IPADM_NVP_AOBJNAME
, name
) == 0)
158 (void) nvpair_value_string(nvp
, &aobjname
);
161 return (ipmgmt_nvlist_match(db_nvl
, proto
, ifname
, aobjname
));
165 * Checks if the database nvl, `db_nvl', contains and matches ANY of the passed
166 * in private nvpairs `proto', `ifname' & `aobjname'.
169 ipmgmt_nvlist_contains(nvlist_t
*db_nvl
, const char *proto
,
170 const char *ifname
, char *aobjname
)
172 char *db_ifname
= NULL
, *db_proto
= NULL
;
173 char *db_aobjname
= NULL
;
177 /* walk through db_nvl and retrieve all private nvpairs */
178 for (nvp
= nvlist_next_nvpair(db_nvl
, NULL
); nvp
!= NULL
;
179 nvp
= nvlist_next_nvpair(db_nvl
, nvp
)) {
180 name
= nvpair_name(nvp
);
181 if (strcmp(IPADM_NVP_PROTONAME
, name
) == 0)
182 (void) nvpair_value_string(nvp
, &db_proto
);
183 else if (strcmp(IPADM_NVP_IFNAME
, name
) == 0)
184 (void) nvpair_value_string(nvp
, &db_ifname
);
185 else if (strcmp(IPADM_NVP_AOBJNAME
, name
) == 0)
186 (void) nvpair_value_string(nvp
, &db_aobjname
);
189 if (proto
!= NULL
&& proto
[0] != '\0') {
190 if ((db_proto
== NULL
|| strcmp(proto
, db_proto
) != 0))
193 if (ifname
!= NULL
&& ifname
[0] != '\0') {
194 if ((db_ifname
== NULL
|| strcmp(ifname
, db_ifname
) != 0))
197 if (aobjname
!= NULL
&& aobjname
[0] != '\0') {
198 if ((db_aobjname
== NULL
|| strcmp(aobjname
, db_aobjname
) != 0))
206 * Retrieves the property value from the DB. The property whose value is to be
207 * retrieved is in `pargp->ia_pname'.
211 ipmgmt_db_getprop(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
214 ipmgmt_prop_arg_t
*pargp
= arg
;
215 boolean_t cont
= B_TRUE
;
221 if (!ipmgmt_nvlist_match(db_nvl
, pargp
->ia_module
,
222 pargp
->ia_ifname
, pargp
->ia_aobjname
))
225 if ((err
= nvlist_lookup_string(db_nvl
, pargp
->ia_pname
,
227 (void) strlcpy(pargp
->ia_pval
, pval
, sizeof (pargp
->ia_pval
));
229 * We have retrieved what we are looking for.
243 * Removes the property value from the DB. The property whose value is to be
244 * removed is in `pargp->ia_pname'.
248 ipmgmt_db_resetprop(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
251 ipmgmt_prop_arg_t
*pargp
= arg
;
254 if (!ipmgmt_nvlist_match(db_nvl
, pargp
->ia_module
,
255 pargp
->ia_ifname
, pargp
->ia_aobjname
))
258 if (!nvlist_exists(db_nvl
, pargp
->ia_pname
))
262 * We found the property in the DB. If IPMGMT_REMOVE is not set then
263 * delete the entry from the db. If it is set, then the property is a
264 * multi-valued property so just remove the specified values from DB.
266 if (pargp
->ia_flags
& IPMGMT_REMOVE
) {
268 char *inpval
= pargp
->ia_pval
;
269 char pval
[MAXPROPVALLEN
];
272 *errp
= nvlist_lookup_string(db_nvl
, pargp
->ia_pname
, &dbpval
);
277 * multi-valued properties are represented as comma separated
278 * values. Use string tokenizer functions to split them and
279 * search for the value to be removed.
281 bzero(pval
, sizeof (pval
));
282 if ((val
= strtok_r(dbpval
, ",", &lasts
)) != NULL
) {
283 if (strcmp(val
, inpval
) != 0)
284 (void) strlcat(pval
, val
, MAXPROPVALLEN
);
285 while ((val
= strtok_r(NULL
, ",", &lasts
)) != NULL
) {
286 if (strcmp(val
, inpval
) != 0) {
288 (void) strlcat(pval
, ",",
290 (void) strlcat(pval
, val
,
295 if (strcmp(dbpval
, inpval
) != 0)
301 *errp
= nvlist_add_string(db_nvl
, pargp
->ia_pname
, pval
);
305 (void) memset(buf
, 0, buflen
);
306 if (ipadm_nvlist2str(db_nvl
, buf
, buflen
) == 0) {
307 /* buffer overflow */
314 /* stop the search */
319 * Input arguments can have IPADM_NVP_AOBJNAME or IPADM_NVP_IFNAME. A match is
320 * found, when one of the following occurs first.
321 * - the input aobjname matches the db aobjname. Return the db address.
322 * - the input interface matches the db interface. Return all the
323 * matching db lines with addresses.
327 ipmgmt_db_getaddr(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
330 ipmgmt_getaddr_cbarg_t
*cbarg
= arg
;
331 char *db_aobjname
= NULL
;
332 char *db_ifname
= NULL
;
333 nvlist_t
*db_addr
= NULL
;
334 char name
[IPMGMT_STRSIZE
];
336 boolean_t add_nvl
= B_FALSE
;
338 /* Parse db nvlist */
339 for (nvp
= nvlist_next_nvpair(db_nvl
, NULL
); nvp
!= NULL
;
340 nvp
= nvlist_next_nvpair(db_nvl
, nvp
)) {
341 if (nvpair_type(nvp
) == DATA_TYPE_NVLIST
)
342 (void) nvpair_value_nvlist(nvp
, &db_addr
);
343 else if (strcmp(nvpair_name(nvp
), IPADM_NVP_IFNAME
) == 0)
344 (void) nvpair_value_string(nvp
, &db_ifname
);
345 else if (strcmp(nvpair_name(nvp
), IPADM_NVP_AOBJNAME
) == 0)
346 (void) nvpair_value_string(nvp
, &db_aobjname
);
349 if (db_aobjname
== NULL
) /* Not an address */
352 /* Check for a match between the aobjnames or the interface name */
353 if (cbarg
->cb_aobjname
[0] != '\0') {
354 if (strcmp(cbarg
->cb_aobjname
, db_aobjname
) == 0)
356 } else if (cbarg
->cb_ifname
[0] != '\0') {
357 if (strcmp(cbarg
->cb_ifname
, db_ifname
) == 0)
364 (void) snprintf(name
, sizeof (name
), "%s_%d", db_ifname
,
366 *errp
= nvlist_add_nvlist(cbarg
->cb_onvl
, name
, db_nvl
);
374 * This function only gets called if a volatile filesystem version
375 * of the configuration file has been created. This only happens in the
376 * extremely rare case that a request has been made to update the configuration
377 * file at boottime while the root filesystem was read-only. This is
378 * really a rare occurrence now that we don't support UFS root filesystems
379 * any longer. This function will periodically attempt to write the
380 * configuration back to its location on the root filesystem. Success
381 * will indicate that the filesystem is no longer read-only.
385 ipmgmt_db_restore_thread(void *arg
)
391 (void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock
);
392 if (!ipmgmt_rdonly_root
)
394 err
= ipmgmt_cpfile(IPADM_VOL_DB_FILE
, IPADM_DB_FILE
, B_FALSE
);
396 ipmgmt_rdonly_root
= B_FALSE
;
399 (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock
);
401 (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock
);
406 * This function takes the appropriate lock, read or write, based on the
407 * `db_op' and then calls DB walker ipadm_rw_db(). The code is complicated
408 * by the fact that we are not always guaranteed to have a writable root
409 * filesystem since it is possible that we are reading or writing during
410 * bootime while the root filesystem is still read-only. This is, by far,
411 * the exception case. Normally, this function will be called when the
412 * root filesystem is writable. In the unusual case where this is not
413 * true, the configuration file is copied to the volatile file system
414 * and is updated there until the root filesystem becomes writable. At
415 * that time the file will be moved back to its proper location by
416 * ipmgmt_db_restore_thread().
419 ipmgmt_db_walk(db_wfunc_t
*db_walk_func
, void *db_warg
, ipadm_db_op_t db_op
)
427 writeop
= (db_op
!= IPADM_DB_READ
);
429 (void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock
);
430 mode
= IPADM_FILE_MODE
;
432 (void) pthread_rwlock_rdlock(&ipmgmt_dbconf_lock
);
437 * Did a previous write attempt fail? If so, don't even try to
438 * read/write to IPADM_DB_FILE.
440 if (!ipmgmt_rdonly_root
) {
441 err
= ipadm_rw_db(db_walk_func
, db_warg
, IPADM_DB_FILE
,
448 * If we haven't already copied the file to the volatile
449 * file system, do so. This should only happen on a failed
450 * writeop(i.e., we have acquired the write lock above).
452 if (access(IPADM_VOL_DB_FILE
, F_OK
) != 0) {
454 err
= ipmgmt_cpfile(IPADM_DB_FILE
, IPADM_VOL_DB_FILE
, B_TRUE
);
457 (void) pthread_attr_init(&attr
);
458 (void) pthread_attr_setdetachstate(&attr
,
459 PTHREAD_CREATE_DETACHED
);
460 err
= pthread_create(&tid
, &attr
, ipmgmt_db_restore_thread
,
462 (void) pthread_attr_destroy(&attr
);
464 (void) unlink(IPADM_VOL_DB_FILE
);
467 ipmgmt_rdonly_root
= B_TRUE
;
471 * Read/write from the volatile copy.
473 err
= ipadm_rw_db(db_walk_func
, db_warg
, IPADM_VOL_DB_FILE
,
476 (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock
);
481 * Used to add an entry towards the end of DB. It just returns B_TRUE for
482 * every line of the DB. When we reach the end, ipadm_rw_db() adds the
487 ipmgmt_db_add(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
, int *errp
)
493 * This function is used to update or create an entry in DB. The nvlist_t,
494 * `in_nvl', represents the line we are looking for. Once we ensure the right
495 * line from DB, we update that entry.
498 ipmgmt_db_update(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
501 ipadm_dbwrite_cbarg_t
*cb
= arg
;
502 uint_t flags
= cb
->dbw_flags
;
503 nvlist_t
*in_nvl
= cb
->dbw_nvl
;
505 char *name
, *instrval
= NULL
, *dbstrval
= NULL
;
506 char pval
[MAXPROPVALLEN
];
509 if (!ipmgmt_nvlist_intersects(db_nvl
, in_nvl
))
512 for (nvp
= nvlist_next_nvpair(in_nvl
, NULL
); nvp
!= NULL
;
513 nvp
= nvlist_next_nvpair(in_nvl
, nvp
)) {
514 name
= nvpair_name(nvp
);
515 if (!IPADM_PRIV_NVP(name
) && nvlist_exists(db_nvl
, name
))
522 assert(nvpair_type(nvp
) == DATA_TYPE_STRING
);
524 if ((*errp
= nvpair_value_string(nvp
, &instrval
)) != 0)
528 * If IPMGMT_APPEND is set then we are dealing with multi-valued
529 * properties. We append to the entry from the db, with the new value.
531 if (flags
& IPMGMT_APPEND
) {
532 if ((*errp
= nvlist_lookup_string(db_nvl
, name
,
535 (void) snprintf(pval
, MAXPROPVALLEN
, "%s,%s", dbstrval
,
537 if ((*errp
= nvlist_add_string(db_nvl
, name
, pval
)) != 0)
540 /* case of in-line update of a db entry */
541 if ((*errp
= nvlist_add_string(db_nvl
, name
, instrval
)) != 0)
545 (void) memset(buf
, 0, buflen
);
546 if (ipadm_nvlist2str(db_nvl
, buf
, buflen
) == 0) {
547 /* buffer overflow */
551 /* we updated the DB entry, so do not continue */
556 * For the given `cbarg->cb_ifname' interface, retrieves any persistent
557 * interface information (used in 'ipadm show-if')
561 ipmgmt_db_getif(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
564 ipmgmt_getif_cbarg_t
*cbarg
= arg
;
565 char *ifname
= cbarg
->cb_ifname
;
567 ipadm_if_info_t
*ifp
= NULL
;
572 if (nvlist_lookup_string(db_nvl
, IPADM_NVP_FAMILY
, &afstr
) != 0 ||
573 nvlist_lookup_string(db_nvl
, IPADM_NVP_IFNAME
, &intf
) != 0 ||
574 (ifname
[0] != '\0' && strcmp(ifname
, intf
) != 0)) {
578 for (ifp
= cbarg
->cb_ifinfo
; ifp
!= NULL
; ifp
= ifp
->ifi_next
) {
579 if (strcmp(ifp
->ifi_name
, intf
) == 0)
583 ipadm_if_info_t
*new;
585 if ((new = calloc(1, sizeof (*new))) == NULL
) {
587 return (B_FALSE
); /* don't continue the walk */
589 new->ifi_next
= cbarg
->cb_ifinfo
;
590 cbarg
->cb_ifinfo
= new;
592 (void) strlcpy(ifp
->ifi_name
, intf
, sizeof (ifp
->ifi_name
));
596 ifp
->ifi_pflags
|= IFIF_IPV4
;
598 assert(af
== AF_INET6
);
599 ifp
->ifi_pflags
|= IFIF_IPV6
;
602 /* Terminate the walk if we found both v4 and v6 interfaces. */
603 if (ifname
[0] != '\0' && (ifp
->ifi_pflags
& IFIF_IPV4
) &&
604 (ifp
->ifi_pflags
& IFIF_IPV6
))
611 * Deletes those entries from the database for which interface name
612 * matches with the given `cbarg->cb_ifname'
616 ipmgmt_db_resetif(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
619 ipmgmt_if_cbarg_t
*cbarg
= arg
;
620 boolean_t isv6
= (cbarg
->cb_family
== AF_INET6
);
621 char *ifname
= cbarg
->cb_ifname
;
626 ipmgmt_aobjmap_t
*head
;
627 boolean_t aobjfound
= B_FALSE
;
631 if (!ipmgmt_nvlist_contains(db_nvl
, NULL
, ifname
, NULL
))
634 if (nvlist_lookup_string(db_nvl
, IPADM_NVP_FAMILY
, &afstr
) == 0) {
635 if (atoi(afstr
) == cbarg
->cb_family
)
640 /* Reset all the interface configurations for 'ifname' */
641 if (isv6
&& (nvlist_exists(db_nvl
, IPADM_NVP_IPV6ADDR
) ||
642 nvlist_exists(db_nvl
, IPADM_NVP_INTFID
))) {
646 (nvlist_exists(db_nvl
, IPADM_NVP_IPV4ADDR
) ||
647 nvlist_exists(db_nvl
, IPADM_NVP_DHCP
))) {
651 if (nvlist_lookup_string(db_nvl
, IPADM_NVP_AOBJNAME
, &aobjname
) == 0) {
653 * This must be an address property. Delete this
654 * line if there is a match in the address family.
656 head
= aobjmap
.aobjmap_head
;
657 while (head
!= NULL
) {
658 if (strcmp(head
->am_aobjname
, aobjname
) == 0) {
660 if (head
->am_family
== cbarg
->cb_family
)
663 head
= head
->am_next
;
666 * If aobjfound = B_FALSE, then this address is not
667 * available in active configuration. We should go ahead
675 * If we are removing both v4 and v6 interface, then we get rid of
676 * all the properties for that interface. On the other hand, if we
677 * are deleting only v4 instance of an interface, then we delete v4
680 if (nvlist_lookup_string(db_nvl
, IPADM_NVP_PROTONAME
, &modstr
) == 0) {
681 proto
= ipadm_str2proto(modstr
);
692 /* this should never be the case, today */
697 /* Not found a match yet. Continue processing the db */
700 /* delete the line from the db */
706 * Deletes those entries from the database for which address object name
707 * matches with the given `cbarg->cb_aobjname'
711 ipmgmt_db_resetaddr(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
714 ipmgmt_resetaddr_cbarg_t
*cbarg
= arg
;
715 char *aobjname
= cbarg
->cb_aobjname
;
718 if (!ipmgmt_nvlist_contains(db_nvl
, NULL
, NULL
, aobjname
))
721 /* delete the line from the db */
727 * Retrieves all interface props, including addresses, for given interface(s).
728 * `invl' contains the list of interfaces, for which information need to be
733 ipmgmt_db_initif(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
736 ipmgmt_initif_cbarg_t
*cbarg
= arg
;
737 nvlist_t
*onvl
= cbarg
->cb_onvl
;
738 nvlist_t
*invl
= cbarg
->cb_invl
;
739 sa_family_t in_af
= cbarg
->cb_family
;
743 if (nvlist_lookup_string(db_nvl
, IPADM_NVP_IFNAME
, &db_ifname
) == 0 &&
744 nvlist_exists(invl
, db_ifname
)) {
745 char name
[IPMGMT_STRSIZE
];
746 sa_family_t db_af
= in_af
;
750 if (in_af
!= AF_UNSPEC
) {
751 if (nvlist_lookup_string(db_nvl
, IPADM_NVP_PROTONAME
,
753 proto
= ipadm_str2proto(pstr
);
754 if (proto
== MOD_PROTO_IPV4
)
756 else if (proto
== MOD_PROTO_IPV6
)
761 if (nvlist_exists(db_nvl
, IPADM_NVP_IPV4ADDR
) ||
762 nvlist_exists(db_nvl
, IPADM_NVP_DHCP
))
768 if (in_af
== db_af
) {
769 (void) snprintf(name
, sizeof (name
), "%s_%d", db_ifname
,
771 *errp
= nvlist_add_nvlist(onvl
, name
, db_nvl
);
780 * helper function for ipmgmt_aobjmap_op(). Adds the node pointed by `nodep'
781 * into `aobjmap' structure.
784 i_ipmgmt_add_amnode(ipmgmt_aobjmap_t
*nodep
)
786 ipmgmt_aobjmap_t
*new, *head
;
788 head
= aobjmap
.aobjmap_head
;
789 if ((new = malloc(sizeof (ipmgmt_aobjmap_t
))) == NULL
)
794 /* Add the node at the beginning of the list */
796 aobjmap
.aobjmap_head
= new;
798 new->am_next
= aobjmap
.aobjmap_head
;
799 aobjmap
.aobjmap_head
= new;
805 * A recursive function to generate alphabetized number given a decimal number.
806 * Decimal 0 to 25 maps to 'a' to 'z' and then the counting continues with 'aa',
810 i_ipmgmt_num2priv_aobjname(uint32_t num
, char **cp
, char *endp
)
813 i_ipmgmt_num2priv_aobjname(num
/ 26 - 1, cp
, endp
);
815 *cp
[0] = 'a' + (num
% 26);
821 * This function generates an `aobjname', when required, and then does
822 * lookup-add. If `nodep->am_aobjname' is not an empty string, then it walks
823 * through the `aobjmap' to check if an address object with the same
824 * `nodep->am_aobjname' exists. If it exists, EEXIST is returned as duplicate
825 * `aobjname's are not allowed.
827 * If `nodep->am_aobjname' is an empty string then the daemon generates an
828 * `aobjname' using the `am_nextnum', which contains the next number to be
829 * used to generate `aobjname'. `am_nextnum' is converted to base26 using
830 * `a-z' alphabets in i_ipmgmt_num2priv_aobjname().
832 * `am_nextnum' will be 0 to begin with. Every time an address object that
833 * needs `aobjname' is added it's incremented by 1. So for the first address
834 * object on net0 the `am_aobjname' will be net0/_a and `am_nextnum' will be 1.
835 * For the second address object on that interface `am_aobjname' will be net0/_b
836 * and `am_nextnum' will incremented to 2.
839 i_ipmgmt_lookupadd_amnode(ipmgmt_aobjmap_t
*nodep
)
841 ipmgmt_aobjmap_t
*head
;
844 for (head
= aobjmap
.aobjmap_head
; head
!= NULL
; head
= head
->am_next
)
845 if (strcmp(head
->am_ifname
, nodep
->am_ifname
) == 0)
847 nextnum
= (head
== NULL
? 0 : head
->am_nextnum
);
850 * if `aobjname' is empty, then the daemon has to generate the
851 * next `aobjname' for the given interface and family.
853 if (nodep
->am_aobjname
[0] == '\0') {
854 char tmpstr
[IPADM_AOBJ_USTRSIZ
- 1]; /* 1 for leading '_' */
856 char *endp
= tmpstr
+ sizeof (tmpstr
);
858 i_ipmgmt_num2priv_aobjname(nextnum
, &cp
, endp
);
864 if (snprintf(nodep
->am_aobjname
, IPADM_AOBJSIZ
, "%s/_%s",
865 nodep
->am_ifname
, tmpstr
) >= IPADM_AOBJSIZ
) {
868 nodep
->am_nextnum
= ++nextnum
;
870 for (head
= aobjmap
.aobjmap_head
; head
!= NULL
;
871 head
= head
->am_next
) {
872 if (strcmp(head
->am_aobjname
, nodep
->am_aobjname
) == 0)
875 nodep
->am_nextnum
= nextnum
;
877 return (i_ipmgmt_add_amnode(nodep
));
881 * Performs following operations on the global `aobjmap' linked list.
882 * (a) ADDROBJ_ADD: add or update address object in `aobjmap'
883 * (b) ADDROBJ_DELETE: delete address object from `aobjmap'
884 * (c) ADDROBJ_LOOKUPADD: place a stub address object in `aobjmap'
885 * (d) ADDROBJ_SETLIFNUM: Sets the lifnum for an address object in `aobjmap'
888 ipmgmt_aobjmap_op(ipmgmt_aobjmap_t
*nodep
, uint32_t op
)
890 ipmgmt_aobjmap_t
*head
, *prev
, *matched
= NULL
;
891 boolean_t update
= B_TRUE
;
895 (void) pthread_rwlock_wrlock(&aobjmap
.aobjmap_rwlock
);
897 head
= aobjmap
.aobjmap_head
;
901 * check for stub nodes (added by ADDROBJ_LOOKUPADD) and
902 * update, else add the new node.
904 for (; head
!= NULL
; head
= head
->am_next
) {
906 * For IPv6, we need to distinguish between the
907 * linklocal and non-linklocal nodes
909 if (strcmp(head
->am_aobjname
,
910 nodep
->am_aobjname
) == 0 &&
911 (head
->am_atype
!= IPADM_ADDR_IPV6_ADDRCONF
||
912 head
->ipmgmt_am_linklocal
==
913 nodep
->ipmgmt_am_linklocal
))
918 /* update the node */
919 (void) strlcpy(head
->am_ifname
, nodep
->am_ifname
,
920 sizeof (head
->am_ifname
));
921 head
->am_lnum
= nodep
->am_lnum
;
922 head
->am_family
= nodep
->am_family
;
923 head
->am_flags
= nodep
->am_flags
;
924 head
->am_atype
= nodep
->am_atype
;
925 head
->am_atype_cache
= nodep
->am_atype_cache
;
927 for (head
= aobjmap
.aobjmap_head
; head
!= NULL
;
928 head
= head
->am_next
) {
929 if (strcmp(head
->am_ifname
,
930 nodep
->am_ifname
) == 0)
933 nodep
->am_nextnum
= (head
== NULL
? 0 :
935 err
= i_ipmgmt_add_amnode(nodep
);
937 db_op
= IPADM_DB_WRITE
;
941 while (head
!= NULL
) {
942 if (strcmp(head
->am_aobjname
,
943 nodep
->am_aobjname
) == 0) {
944 nodep
->am_atype
= head
->am_atype
;
946 * There could be multiple IPV6_ADDRCONF nodes,
947 * with same address object name, so check for
948 * logical number also.
950 if (head
->am_atype
!=
951 IPADM_ADDR_IPV6_ADDRCONF
||
952 nodep
->am_lnum
== head
->am_lnum
)
956 head
= head
->am_next
;
960 * If the address object is in both active and
961 * persistent configuration and the user is deleting it
962 * only from active configuration then mark this node
963 * for deletion by reseting IPMGMT_ACTIVE bit.
964 * With this the same address object name cannot
965 * be reused until it is permanently removed.
967 if (head
->am_flags
== (IPMGMT_ACTIVE
|IPMGMT_PERSIST
) &&
968 nodep
->am_flags
== IPMGMT_ACTIVE
) {
969 /* Update flags in the in-memory map. */
970 head
->am_flags
&= ~IPMGMT_ACTIVE
;
973 /* Update info in file. */
974 db_op
= IPADM_DB_WRITE
;
977 (void) strlcpy(nodep
->am_ifname
,
979 sizeof (nodep
->am_ifname
));
980 /* otherwise delete the node */
981 if (head
== aobjmap
.aobjmap_head
)
982 aobjmap
.aobjmap_head
= head
->am_next
;
984 prev
->am_next
= head
->am_next
;
986 db_op
= IPADM_DB_DELETE
;
992 case ADDROBJ_LOOKUPADD
:
993 err
= i_ipmgmt_lookupadd_amnode(nodep
);
996 case ADDROBJ_SETLIFNUM
:
998 for (; head
!= NULL
; head
= head
->am_next
) {
999 if (strcmp(head
->am_ifname
,
1000 nodep
->am_ifname
) == 0 &&
1001 head
->am_family
== nodep
->am_family
&&
1002 head
->am_lnum
== nodep
->am_lnum
) {
1006 if (strcmp(head
->am_aobjname
,
1007 nodep
->am_aobjname
) == 0) {
1013 if (matched
!= NULL
) {
1014 /* update the lifnum */
1015 matched
->am_lnum
= nodep
->am_lnum
;
1024 if (err
== 0 && update
)
1025 err
= ipmgmt_persist_aobjmap(nodep
, db_op
);
1027 (void) pthread_rwlock_unlock(&aobjmap
.aobjmap_rwlock
);
1033 * Given a node in `aobjmap', this function converts it into nvlist_t structure.
1034 * The content to be written to DB must be represented as nvlist_t.
1037 i_ipmgmt_node2nvl(nvlist_t
**nvl
, ipmgmt_aobjmap_t
*np
)
1040 char strval
[IPMGMT_STRSIZE
];
1043 if ((err
= nvlist_alloc(nvl
, NV_UNIQUE_NAME
, 0)) != 0)
1046 if ((err
= nvlist_add_string(*nvl
, IPADM_NVP_AOBJNAME
,
1047 np
->am_aobjname
)) != 0)
1050 if ((err
= nvlist_add_string(*nvl
, IPADM_NVP_IFNAME
,
1051 np
->am_ifname
)) != 0)
1054 (void) snprintf(strval
, IPMGMT_STRSIZE
, "%d", np
->am_lnum
);
1055 if ((err
= nvlist_add_string(*nvl
, IPADM_NVP_LIFNUM
, strval
)) != 0)
1058 (void) snprintf(strval
, IPMGMT_STRSIZE
, "%d", np
->am_family
);
1059 if ((err
= nvlist_add_string(*nvl
, IPADM_NVP_FAMILY
, strval
)) != 0)
1062 (void) snprintf(strval
, IPMGMT_STRSIZE
, "%d", np
->am_flags
);
1063 if ((err
= nvlist_add_string(*nvl
, FLAGS
, strval
)) != 0)
1066 (void) snprintf(strval
, IPMGMT_STRSIZE
, "%d", np
->am_atype
);
1067 if ((err
= nvlist_add_string(*nvl
, ATYPE
, strval
)) != 0)
1070 switch (np
->am_atype
) {
1071 case IPADM_ADDR_IPV6_ADDRCONF
: {
1072 struct sockaddr_in6
*in6
;
1074 in6
= &np
->ipmgmt_am_ifid
;
1075 if (np
->ipmgmt_am_linklocal
&&
1076 IN6_IS_ADDR_UNSPECIFIED(&in6
->sin6_addr
)) {
1077 if ((err
= nvlist_add_string(*nvl
,
1078 IPADM_NVP_IPNUMADDR
, "default")) != 0) {
1082 if (inet_ntop(AF_INET6
, &in6
->sin6_addr
, strval
,
1083 IPMGMT_STRSIZE
) == NULL
) {
1087 if ((err
= nvlist_add_string(*nvl
,
1088 IPADM_NVP_IPNUMADDR
, strval
)) != 0) {
1094 case IPADM_ADDR_DHCP
: {
1095 if (np
->ipmgmt_am_reqhost
&&
1096 *np
->ipmgmt_am_reqhost
!= '\0' &&
1097 (err
= nvlist_add_string(*nvl
, IPADM_NVP_REQHOST
,
1098 np
->ipmgmt_am_reqhost
)) != 0)
1103 if ((err
= nvlist_add_string(*nvl
, IPADM_NVP_IPNUMADDR
,
1115 * Read the aobjmap data store and build the in-memory representation
1116 * of the aobjmap. We don't need to hold any locks while building this as
1117 * we do this in very early stage of daemon coming up, even before the door
1122 ipmgmt_aobjmap_init(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
1125 nvpair_t
*nvp
= NULL
;
1126 char *name
, *strval
= NULL
;
1127 ipmgmt_aobjmap_t node
;
1128 struct sockaddr_in6
*in6
;
1131 node
.am_next
= NULL
;
1132 for (nvp
= nvlist_next_nvpair(db_nvl
, NULL
); nvp
!= NULL
;
1133 nvp
= nvlist_next_nvpair(db_nvl
, nvp
)) {
1134 name
= nvpair_name(nvp
);
1136 if ((*errp
= nvpair_value_string(nvp
, &strval
)) != 0)
1138 if (strcmp(IPADM_NVP_AOBJNAME
, name
) == 0) {
1139 (void) strlcpy(node
.am_aobjname
, strval
,
1140 sizeof (node
.am_aobjname
));
1141 } else if (strcmp(IPADM_NVP_IFNAME
, name
) == 0) {
1142 (void) strlcpy(node
.am_ifname
, strval
,
1143 sizeof (node
.am_ifname
));
1144 } else if (strcmp(IPADM_NVP_LIFNUM
, name
) == 0) {
1145 node
.am_lnum
= atoi(strval
);
1146 } else if (strcmp(IPADM_NVP_FAMILY
, name
) == 0) {
1147 node
.am_family
= (sa_family_t
)atoi(strval
);
1148 } else if (strcmp(FLAGS
, name
) == 0) {
1149 node
.am_flags
= atoi(strval
);
1150 } else if (strcmp(ATYPE
, name
) == 0) {
1151 node
.am_atype
= (ipadm_addr_type_t
)atoi(strval
);
1152 } else if (strcmp(IPADM_NVP_IPNUMADDR
, name
) == 0) {
1153 if (node
.am_atype
== IPADM_ADDR_IPV6_ADDRCONF
) {
1154 in6
= &node
.ipmgmt_am_ifid
;
1155 if (strcmp(strval
, "default") == 0) {
1157 sizeof (node
.ipmgmt_am_ifid
));
1158 node
.ipmgmt_am_linklocal
= B_TRUE
;
1160 (void) inet_pton(AF_INET6
, strval
,
1162 if (IN6_IS_ADDR_UNSPECIFIED(
1164 node
.ipmgmt_am_linklocal
=
1171 /* we have all the information we need, add the node */
1172 *errp
= i_ipmgmt_add_amnode(&node
);
1178 * Updates an entry from the temporary cache file, which matches the given
1179 * address object name.
1183 ipmgmt_update_aobjmap(void *arg
, nvlist_t
*db_nvl
, char *buf
,
1184 size_t buflen
, int *errp
)
1186 ipadm_dbwrite_cbarg_t
*cb
= arg
;
1187 nvlist_t
*in_nvl
= cb
->dbw_nvl
;
1188 uint32_t flags
= cb
->dbw_flags
;
1189 char *db_lifnumstr
= NULL
, *in_lifnumstr
= NULL
;
1192 if (!ipmgmt_nvlist_intersects(db_nvl
, in_nvl
))
1195 if (flags
& IPMGMT_ATYPE_V6ACONF
) {
1196 if (nvlist_lookup_string(db_nvl
, IPADM_NVP_LIFNUM
,
1197 &db_lifnumstr
) != 0 ||
1198 nvlist_lookup_string(in_nvl
, IPADM_NVP_LIFNUM
,
1199 &in_lifnumstr
) != 0 ||
1200 (atoi(db_lifnumstr
) != -1 && atoi(in_lifnumstr
) != -1 &&
1201 strcmp(db_lifnumstr
, in_lifnumstr
) != 0))
1205 /* we found the match */
1206 (void) memset(buf
, 0, buflen
);
1207 if (ipadm_nvlist2str(in_nvl
, buf
, buflen
) == 0) {
1208 /* buffer overflow */
1212 /* stop the walker */
1217 * Deletes an entry from the temporary cache file, which matches the given
1218 * address object name.
1222 ipmgmt_delete_aobjmap(void *arg
, nvlist_t
*db_nvl
, char *buf
,
1223 size_t buflen
, int *errp
)
1225 ipmgmt_aobjmap_t
*nodep
= arg
;
1226 char *db_lifnumstr
= NULL
;
1229 if (!ipmgmt_nvlist_match(db_nvl
, NULL
, nodep
->am_ifname
,
1230 nodep
->am_aobjname
))
1233 if (nodep
->am_atype
== IPADM_ADDR_IPV6_ADDRCONF
) {
1234 if (nvlist_lookup_string(db_nvl
, IPADM_NVP_LIFNUM
,
1235 &db_lifnumstr
) != 0 || atoi(db_lifnumstr
) != nodep
->am_lnum
)
1239 /* we found the match, delete the line from the db */
1242 /* stop the walker */
1247 * Adds or deletes aobjmap node information into a temporary cache file.
1250 ipmgmt_persist_aobjmap(ipmgmt_aobjmap_t
*nodep
, ipadm_db_op_t op
)
1253 ipadm_dbwrite_cbarg_t cb
;
1254 nvlist_t
*nvl
= NULL
;
1256 if (op
== IPADM_DB_WRITE
) {
1257 if ((err
= i_ipmgmt_node2nvl(&nvl
, nodep
)) != 0)
1260 if (nodep
->am_atype
== IPADM_ADDR_IPV6_ADDRCONF
)
1261 cb
.dbw_flags
= IPMGMT_ATYPE_V6ACONF
;
1265 err
= ipadm_rw_db(ipmgmt_update_aobjmap
, &cb
,
1266 ADDROBJ_MAPPING_DB_FILE
, IPADM_FILE_MODE
, IPADM_DB_WRITE
);
1269 assert(op
== IPADM_DB_DELETE
);
1271 err
= ipadm_rw_db(ipmgmt_delete_aobjmap
, nodep
,
1272 ADDROBJ_MAPPING_DB_FILE
, IPADM_FILE_MODE
, IPADM_DB_DELETE
);
1278 * upgrades the ipadm data-store. It renames all the old private protocol
1279 * property names which start with leading protocol names to begin with
1280 * IPADM_PRIV_PROP_PREFIX.
1284 ipmgmt_db_upgrade(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
1288 char *name
, *pname
= NULL
, *protostr
= NULL
, *pval
= NULL
;
1289 uint_t proto
, nproto
;
1290 char nname
[IPMGMT_STRSIZE
], tmpstr
[IPMGMT_STRSIZE
];
1294 * We are interested in lines which contain protocol properties. We
1295 * walk through other lines in the DB.
1297 if (nvlist_exists(db_nvl
, IPADM_NVP_IFNAME
) ||
1298 nvlist_exists(db_nvl
, IPADM_NVP_AOBJNAME
)) {
1301 assert(nvlist_exists(db_nvl
, IPADM_NVP_PROTONAME
));
1304 * extract the propname from the `db_nvl' and also extract the
1305 * protocol from the `db_nvl'.
1307 for (nvp
= nvlist_next_nvpair(db_nvl
, NULL
); nvp
!= NULL
;
1308 nvp
= nvlist_next_nvpair(db_nvl
, nvp
)) {
1309 name
= nvpair_name(nvp
);
1310 if (strcmp(name
, IPADM_NVP_PROTONAME
) == 0) {
1311 if (nvpair_value_string(nvp
, &protostr
) != 0)
1314 assert(!IPADM_PRIV_NVP(name
));
1316 if (nvpair_value_string(nvp
, &pval
) != 0)
1321 /* if the private property is in the right format return */
1322 if (strncmp(pname
, IPADM_PERSIST_PRIVPROP_PREFIX
,
1323 strlen(IPADM_PERSIST_PRIVPROP_PREFIX
)) == 0) {
1326 /* if it's a public property move onto the next property */
1327 nproto
= proto
= ipadm_str2proto(protostr
);
1328 if (ipadm_legacy2new_propname(pname
, nname
, sizeof (nname
),
1333 /* replace the old protocol with new protocol, if required */
1334 if (nproto
!= proto
) {
1335 protostr
= ipadm_proto2str(nproto
);
1336 if (nvlist_add_string(db_nvl
, IPADM_NVP_PROTONAME
,
1342 /* replace the old property name with new property name, if required */
1343 /* add the prefix to property name */
1344 (void) snprintf(tmpstr
, sizeof (tmpstr
), "_%s", nname
);
1345 if (nvlist_add_string(db_nvl
, tmpstr
, pval
) != 0 ||
1346 nvlist_remove(db_nvl
, pname
, DATA_TYPE_STRING
) != 0) {
1349 (void) memset(buf
, 0, buflen
);
1350 if (ipadm_nvlist2str(db_nvl
, buf
, buflen
) == 0) {
1351 /* buffer overflow */
1358 * Called during boot.
1360 * Walk through the DB and apply all the global module properties. We plow
1361 * through the DB even if we fail to apply property.
1365 ipmgmt_db_init(void *cbarg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
1368 ipadm_handle_t iph
= cbarg
;
1369 nvpair_t
*nvp
, *pnvp
;
1370 char *strval
= NULL
, *name
, *mod
= NULL
, *pname
;
1371 char tmpstr
[IPMGMT_STRSIZE
];
1375 * We could have used nvl_exists() directly, however we need several
1376 * calls to it and each call traverses the list. Since this codepath
1377 * is exercised during boot, let's traverse the list ourselves and do
1378 * the necessary checks.
1380 for (nvp
= nvlist_next_nvpair(db_nvl
, NULL
); nvp
!= NULL
;
1381 nvp
= nvlist_next_nvpair(db_nvl
, nvp
)) {
1382 name
= nvpair_name(nvp
);
1383 if (IPADM_PRIV_NVP(name
)) {
1384 if (strcmp(name
, IPADM_NVP_IFNAME
) == 0 ||
1385 strcmp(name
, IPADM_NVP_AOBJNAME
) == 0)
1387 else if (strcmp(name
, IPADM_NVP_PROTONAME
) == 0 &&
1388 nvpair_value_string(nvp
, &mod
) != 0)
1391 /* possible a property */
1396 /* if we are here than we found a global property */
1397 assert(mod
!= NULL
);
1398 assert(nvpair_type(pnvp
) == DATA_TYPE_STRING
);
1400 proto
= ipadm_str2proto(mod
);
1401 name
= nvpair_name(pnvp
);
1402 if (nvpair_value_string(pnvp
, &strval
) == 0) {
1403 if (strncmp(name
, IPADM_PERSIST_PRIVPROP_PREFIX
,
1404 strlen(IPADM_PERSIST_PRIVPROP_PREFIX
)) == 0) {
1405 /* private protocol property */
1407 } else if (ipadm_legacy2new_propname(name
, tmpstr
,
1408 sizeof (tmpstr
), &proto
) == 0) {
1413 if (ipadm_set_prop(iph
, pname
, strval
, proto
,
1414 IPADM_OPT_ACTIVE
) != IPADM_SUCCESS
) {
1415 ipmgmt_log(LOG_WARNING
, "Failed to reapply property %s",
1423 /* initialize global module properties */
1427 ipadm_handle_t iph
= NULL
;
1429 if (ipadm_open(&iph
, IPH_INIT
) != IPADM_SUCCESS
) {
1430 ipmgmt_log(LOG_WARNING
, "Could not reapply any of the "
1431 "persisted protocol properties");
1434 /* ipmgmt_db_init() logs warnings if there are any issues */
1435 (void) ipmgmt_db_walk(ipmgmt_db_init
, iph
, IPADM_DB_READ
);
1440 ipmgmt_release_scf_resources(scf_resources_t
*res
)
1442 scf_entry_destroy(res
->sr_ent
);
1443 scf_transaction_destroy(res
->sr_tx
);
1444 scf_value_destroy(res
->sr_val
);
1445 scf_property_destroy(res
->sr_prop
);
1446 scf_pg_destroy(res
->sr_pg
);
1447 scf_instance_destroy(res
->sr_inst
);
1448 (void) scf_handle_unbind(res
->sr_handle
);
1449 scf_handle_destroy(res
->sr_handle
);
1453 * It creates the necessary SCF handles and binds the given `fmri' to an
1454 * instance. These resources are required for retrieving property value,
1455 * creating property groups and modifying property values.
1458 ipmgmt_create_scf_resources(const char *fmri
, scf_resources_t
*res
)
1462 res
->sr_inst
= NULL
;
1464 res
->sr_prop
= NULL
;
1467 if ((res
->sr_handle
= scf_handle_create(SCF_VERSION
)) == NULL
)
1470 if (scf_handle_bind(res
->sr_handle
) != 0) {
1471 scf_handle_destroy(res
->sr_handle
);
1474 if ((res
->sr_inst
= scf_instance_create(res
->sr_handle
)) == NULL
)
1476 if (scf_handle_decode_fmri(res
->sr_handle
, fmri
, NULL
, NULL
,
1477 res
->sr_inst
, NULL
, NULL
, SCF_DECODE_FMRI_REQUIRE_INSTANCE
) != 0) {
1480 /* we will create the rest of the resources on demand */
1484 ipmgmt_log(LOG_WARNING
, "failed to create scf resources: %s",
1485 scf_strerror(scf_error()));
1486 ipmgmt_release_scf_resources(res
);
1491 * persists the `pval' for a given property `pname' in SCF. The only supported
1492 * SCF property types are INTEGER and ASTRING.
1495 ipmgmt_set_scfprop_value(scf_resources_t
*res
, const char *pname
, void *pval
,
1501 if ((res
->sr_val
= scf_value_create(res
->sr_handle
)) == NULL
)
1504 case SCF_TYPE_INTEGER
:
1505 scf_value_set_integer(res
->sr_val
, *(int64_t *)pval
);
1507 case SCF_TYPE_ASTRING
:
1508 if (scf_value_set_astring(res
->sr_val
, (char *)pval
) != 0) {
1509 ipmgmt_log(LOG_WARNING
, "Error setting string value %s "
1510 "for property %s: %s", pval
, pname
,
1511 scf_strerror(scf_error()));
1519 if ((res
->sr_tx
= scf_transaction_create(res
->sr_handle
)) == NULL
)
1521 if ((res
->sr_ent
= scf_entry_create(res
->sr_handle
)) == NULL
)
1523 if ((res
->sr_prop
= scf_property_create(res
->sr_handle
)) == NULL
)
1527 new = (scf_pg_get_property(res
->sr_pg
, pname
, res
->sr_prop
) != 0);
1528 if (scf_transaction_start(res
->sr_tx
, res
->sr_pg
) == -1)
1531 if (scf_transaction_property_new(res
->sr_tx
, res
->sr_ent
,
1532 pname
, ptype
) == -1) {
1536 if (scf_transaction_property_change(res
->sr_tx
, res
->sr_ent
,
1537 pname
, ptype
) == -1) {
1542 if (scf_entry_add_value(res
->sr_ent
, res
->sr_val
) != 0)
1545 result
= scf_transaction_commit(res
->sr_tx
);
1547 scf_transaction_reset(res
->sr_tx
);
1548 if (scf_pg_update(res
->sr_pg
) == -1) {
1558 ipmgmt_log(LOG_WARNING
, "failed to save the data in SCF: %s",
1559 scf_strerror(scf_error()));
1564 * Given a `pgname'/`pname', it retrieves the value based on `ptype' and
1565 * places it in `pval'.
1568 ipmgmt_get_scfprop(scf_resources_t
*res
, const char *pgname
, const char *pname
,
1569 void *pval
, scf_type_t ptype
)
1572 scf_simple_prop_t
*prop
;
1574 prop
= scf_simple_prop_get(res
->sr_handle
, IPMGMTD_FMRI
, pgname
, pname
);
1575 numvals
= scf_simple_prop_numvalues(prop
);
1579 case SCF_TYPE_INTEGER
:
1580 *(int64_t **)pval
= scf_simple_prop_next_integer(prop
);
1582 case SCF_TYPE_ASTRING
:
1583 *(char **)pval
= scf_simple_prop_next_astring(prop
);
1587 scf_simple_prop_free(prop
);
1592 * It stores the `pval' for given `pgname'/`pname' property group in SCF.
1595 ipmgmt_set_scfprop(scf_resources_t
*res
, const char *pgname
, const char *pname
,
1596 void *pval
, scf_type_t ptype
)
1600 if ((res
->sr_pg
= scf_pg_create(res
->sr_handle
)) == NULL
) {
1601 ipmgmt_log(LOG_WARNING
, "failed to create property group: %s",
1602 scf_strerror(scf_error()));
1606 if (scf_instance_add_pg(res
->sr_inst
, pgname
, SCF_GROUP_APPLICATION
,
1607 0, res
->sr_pg
) != 0) {
1608 if ((err
= scf_error()) != SCF_ERROR_EXISTS
) {
1609 ipmgmt_log(LOG_WARNING
,
1610 "Error adding property group '%s/%s': %s",
1611 pgname
, pname
, scf_strerror(err
));
1615 * if the property group already exists, then we get the
1616 * composed view of the property group for the given instance.
1618 if (scf_instance_get_pg_composed(res
->sr_inst
, NULL
, pgname
,
1620 ipmgmt_log(LOG_WARNING
, "Error getting composed view "
1621 "of the property group '%s/%s': %s", pgname
, pname
,
1622 scf_strerror(scf_error()));
1627 return (ipmgmt_set_scfprop_value(res
, pname
, pval
, ptype
));
1631 * Returns B_TRUE, if the non-global zone is being booted for the first time
1632 * after being installed. This is required to setup the ipadm data-store for
1633 * the first boot of the non-global zone. Please see, PSARC 2010/166,
1636 * Note that, this API cannot be used to determine first boot post image-update.
1637 * 'pkg image-update' clones the current BE and the existing value of
1638 * ipmgmtd/first_boot_done will be carried forward and obviously it will be set
1642 ipmgmt_ngz_firstboot_postinstall()
1644 scf_resources_t res
;
1645 boolean_t bval
= B_TRUE
;
1648 /* we always err on the side of caution */
1649 if (ipmgmt_create_scf_resources(IPMGMTD_FMRI
, &res
) != 0)
1652 if (ipmgmt_get_scfprop(&res
, IPMGMTD_APP_PG
, IPMGMTD_PROP_FBD
, &strval
,
1653 SCF_TYPE_ASTRING
) > 0) {
1654 bval
= (strcmp(strval
, IPMGMTD_TRUESTR
) == 0 ?
1658 * IPMGMTD_PROP_FBD does not exist in the SCF. Lets create it.
1659 * Since we err on the side of caution, we ignore the return
1660 * error and return B_TRUE.
1662 (void) ipmgmt_set_scfprop(&res
, IPMGMTD_APP_PG
,
1663 IPMGMTD_PROP_FBD
, IPMGMTD_TRUESTR
, SCF_TYPE_ASTRING
);
1665 ipmgmt_release_scf_resources(&res
);
1670 * Returns B_TRUE, if the data-store needs upgrade otherwise returns B_FALSE.
1671 * Today we have to take care of, one case of, upgrading from version 0 to
1672 * version 1, so we will use boolean_t as means to decide if upgrade is needed
1673 * or not. Further, the upcoming projects might completely move the flatfile
1674 * data-store into SCF and hence we shall keep this interface simple.
1677 ipmgmt_needs_upgrade(scf_resources_t
*res
)
1679 boolean_t bval
= B_TRUE
;
1682 if (ipmgmt_get_scfprop(res
, IPMGMTD_APP_PG
, IPMGMTD_PROP_DBVER
,
1683 &verp
, SCF_TYPE_INTEGER
) > 0) {
1684 if (*verp
== IPADM_DB_VERSION
)
1688 * 'datastore_version' doesn't exist. Which means that we need to
1689 * upgrade the datastore. We will create 'datastore_version' and set
1690 * the version value to IPADM_DB_VERSION, after we upgrade the file.
1696 * This is called after the successful upgrade of the local data-store. With
1697 * the data-store upgraded to recent version we don't have to do anything on
1698 * subsequent reboots.
1701 ipmgmt_update_dbver(scf_resources_t
*res
)
1703 int64_t version
= IPADM_DB_VERSION
;
1705 (void) ipmgmt_set_scfprop(res
, IPMGMTD_APP_PG
,
1706 IPMGMTD_PROP_DBVER
, &version
, SCF_TYPE_INTEGER
);