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 2018 Joyent, Inc.
25 * Copyright 2016 Argo Technologie SA.
26 * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
30 * Contains DB walker functions, which are of type `db_wfunc_t';
32 * typedef boolean_t db_wfunc_t(void *cbarg, nvlist_t *db_nvl, char *buf,
33 * size_t bufsize, int *errp);
35 * ipadm_rw_db() walks through the data store, one line at a time and calls
36 * these call back functions with:
37 * `cbarg' - callback argument
38 * `db_nvl' - representing a line from DB in nvlist_t form
39 * `buf' - character buffer to hold modified line
40 * `bufsize'- size of the buffer
41 * `errp' - captures any error inside the walker function.
43 * All the 'write' callback functions modify `db_nvl' based on `cbarg' and
44 * copy string representation of `db_nvl' (using ipadm_nvlist2str()) into `buf'.
45 * To delete a line from the DB, buf[0] is set to `\0'. Inside ipadm_rw_db(),
46 * the modified `buf' is written back into DB.
48 * All the 'read' callback functions, retrieve the information from the DB, by
49 * reading `db_nvl' and then populate the `cbarg'.
56 #include <sys/types.h>
57 #include <sys/socket.h>
58 #include <netinet/in.h>
59 #include <arpa/inet.h>
61 #include "ipmgmt_impl.h"
63 /* SCF related property group names and property names */
64 #define IPMGMTD_APP_PG "ipmgmtd"
65 #define IPMGMTD_PROP_FBD "first_boot_done"
66 #define IPMGMTD_PROP_DBVER "datastore_version"
67 #define IPMGMTD_TRUESTR "true"
69 #define ATYPE "_atype" /* name of the address type nvpair */
70 #define FLAGS "_flags" /* name of the flags nvpair */
73 * flag used by ipmgmt_persist_aobjmap() to indicate address type is
74 * IPADM_ADDR_IPV6_ADDRCONF.
76 #define IPMGMT_ATYPE_V6ACONF 0x1
78 extern pthread_rwlock_t ipmgmt_dbconf_lock
;
80 /* signifies whether volatile copy of data store is in use */
81 static boolean_t ipmgmt_rdonly_root
= B_FALSE
;
84 * Checks if the database nvl, `db_nvl' contains and matches ALL of the passed
85 * in private nvpairs `proto', `ifname' & `aobjname'.
88 ipmgmt_nvlist_match(nvlist_t
*db_nvl
, const char *proto
, const char *ifname
,
91 char *db_proto
= NULL
, *db_ifname
= NULL
;
92 char *db_aobjname
= NULL
;
96 /* walk through db_nvl and retrieve all its private nvpairs */
97 for (nvp
= nvlist_next_nvpair(db_nvl
, NULL
); nvp
!= NULL
;
98 nvp
= nvlist_next_nvpair(db_nvl
, nvp
)) {
99 name
= nvpair_name(nvp
);
100 if (strcmp(IPADM_NVP_PROTONAME
, name
) == 0)
101 (void) nvpair_value_string(nvp
, &db_proto
);
102 else if (strcmp(IPADM_NVP_IFNAME
, name
) == 0)
103 (void) nvpair_value_string(nvp
, &db_ifname
);
104 else if (strcmp(IPADM_NVP_AOBJNAME
, name
) == 0)
105 (void) nvpair_value_string(nvp
, &db_aobjname
);
108 if (proto
!= NULL
&& proto
[0] == '\0')
110 if (ifname
!= NULL
&& ifname
[0] == '\0')
112 if (aobjname
!= NULL
&& aobjname
[0] == '\0')
115 if ((proto
== NULL
&& db_proto
!= NULL
) ||
116 (proto
!= NULL
&& db_proto
== NULL
) ||
117 (proto
!= NULL
&& db_proto
!= NULL
&&
118 strcmp(proto
, db_proto
) != 0)) {
119 /* no intersection - different protocols. */
122 if ((ifname
== NULL
&& db_ifname
!= NULL
) ||
123 (ifname
!= NULL
&& db_ifname
== NULL
) ||
124 (ifname
!= NULL
&& db_ifname
!= NULL
&&
125 strcmp(ifname
, db_ifname
) != 0)) {
126 /* no intersection - different interfaces. */
129 if ((aobjname
== NULL
&& db_aobjname
!= NULL
) ||
130 (aobjname
!= NULL
&& db_aobjname
== NULL
) ||
131 (aobjname
!= NULL
&& db_aobjname
!= NULL
&&
132 strcmp(aobjname
, db_aobjname
) != 0)) {
133 /* no intersection - different address objects */
141 * Checks if the database nvl, `db_nvl' and the input nvl, `in_nvl' intersects.
144 ipmgmt_nvlist_intersects(nvlist_t
*db_nvl
, nvlist_t
*in_nvl
)
148 char *proto
= NULL
, *ifname
= NULL
, *aobjname
= NULL
;
150 /* walk through in_nvl and retrieve all its private nvpairs */
151 for (nvp
= nvlist_next_nvpair(in_nvl
, NULL
); nvp
!= NULL
;
152 nvp
= nvlist_next_nvpair(in_nvl
, nvp
)) {
153 name
= nvpair_name(nvp
);
154 if (strcmp(IPADM_NVP_PROTONAME
, name
) == 0)
155 (void) nvpair_value_string(nvp
, &proto
);
156 else if (strcmp(IPADM_NVP_IFNAME
, name
) == 0)
157 (void) nvpair_value_string(nvp
, &ifname
);
158 else if (strcmp(IPADM_NVP_AOBJNAME
, name
) == 0)
159 (void) nvpair_value_string(nvp
, &aobjname
);
162 return (ipmgmt_nvlist_match(db_nvl
, proto
, ifname
, aobjname
));
166 * Checks if the database nvl, `db_nvl', contains and matches ANY of the passed
167 * in private nvpairs `proto', `ifname' & `aobjname'.
170 ipmgmt_nvlist_contains(nvlist_t
*db_nvl
, const char *proto
,
171 const char *ifname
, char *aobjname
)
173 char *db_ifname
= NULL
, *db_proto
= NULL
;
174 char *db_aobjname
= NULL
;
178 /* walk through db_nvl and retrieve all private nvpairs */
179 for (nvp
= nvlist_next_nvpair(db_nvl
, NULL
); nvp
!= NULL
;
180 nvp
= nvlist_next_nvpair(db_nvl
, nvp
)) {
181 name
= nvpair_name(nvp
);
182 if (strcmp(IPADM_NVP_PROTONAME
, name
) == 0)
183 (void) nvpair_value_string(nvp
, &db_proto
);
184 else if (strcmp(IPADM_NVP_IFNAME
, name
) == 0)
185 (void) nvpair_value_string(nvp
, &db_ifname
);
186 else if (strcmp(IPADM_NVP_AOBJNAME
, name
) == 0)
187 (void) nvpair_value_string(nvp
, &db_aobjname
);
190 if (proto
!= NULL
&& proto
[0] != '\0') {
191 if ((db_proto
== NULL
|| strcmp(proto
, db_proto
) != 0))
194 if (ifname
!= NULL
&& ifname
[0] != '\0') {
195 if ((db_ifname
== NULL
|| strcmp(ifname
, db_ifname
) != 0))
198 if (aobjname
!= NULL
&& aobjname
[0] != '\0') {
199 if ((db_aobjname
== NULL
|| strcmp(aobjname
, db_aobjname
) != 0))
207 * Retrieves the property value from the DB. The property whose value is to be
208 * retrieved is in `pargp->ia_pname'.
212 ipmgmt_db_getprop(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
215 ipmgmt_prop_arg_t
*pargp
= arg
;
216 boolean_t cont
= B_TRUE
;
222 if (!ipmgmt_nvlist_match(db_nvl
, pargp
->ia_module
,
223 pargp
->ia_ifname
, pargp
->ia_aobjname
))
226 if ((err
= nvlist_lookup_string(db_nvl
, pargp
->ia_pname
,
228 (void) strlcpy(pargp
->ia_pval
, pval
, sizeof (pargp
->ia_pval
));
230 * We have retrieved what we are looking for.
244 * Removes the property value from the DB. The property whose value is to be
245 * removed is in `pargp->ia_pname'.
249 ipmgmt_db_resetprop(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
252 ipmgmt_prop_arg_t
*pargp
= arg
;
255 if (!ipmgmt_nvlist_match(db_nvl
, pargp
->ia_module
,
256 pargp
->ia_ifname
, pargp
->ia_aobjname
))
259 if (!nvlist_exists(db_nvl
, pargp
->ia_pname
))
263 * We found the property in the DB. If IPMGMT_REMOVE is not set then
264 * delete the entry from the db. If it is set, then the property is a
265 * multi-valued property so just remove the specified values from DB.
267 if (pargp
->ia_flags
& IPMGMT_REMOVE
) {
269 char *inpval
= pargp
->ia_pval
;
270 char pval
[MAXPROPVALLEN
];
273 *errp
= nvlist_lookup_string(db_nvl
, pargp
->ia_pname
, &dbpval
);
278 * multi-valued properties are represented as comma separated
279 * values. Use string tokenizer functions to split them and
280 * search for the value to be removed.
282 bzero(pval
, sizeof (pval
));
283 if ((val
= strtok_r(dbpval
, ",", &lasts
)) != NULL
) {
284 if (strcmp(val
, inpval
) != 0)
285 (void) strlcat(pval
, val
, MAXPROPVALLEN
);
286 while ((val
= strtok_r(NULL
, ",", &lasts
)) != NULL
) {
287 if (strcmp(val
, inpval
) != 0) {
289 (void) strlcat(pval
, ",",
291 (void) strlcat(pval
, val
,
296 if (strcmp(dbpval
, inpval
) != 0)
302 *errp
= nvlist_add_string(db_nvl
, pargp
->ia_pname
, pval
);
306 (void) memset(buf
, 0, buflen
);
307 if (ipadm_nvlist2str(db_nvl
, buf
, buflen
) == 0) {
308 /* buffer overflow */
315 /* stop the search */
320 * Input arguments can have IPADM_NVP_AOBJNAME or IPADM_NVP_IFNAME. A match is
321 * found, when one of the following occurs first.
322 * - the input aobjname matches the db aobjname. Return the db address.
323 * - the input interface matches the db interface. Return all the
324 * matching db lines with addresses.
328 ipmgmt_db_getaddr(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
331 ipmgmt_getaddr_cbarg_t
*cbarg
= arg
;
332 char *db_aobjname
= NULL
;
333 char *db_ifname
= NULL
;
334 nvlist_t
*db_addr
= NULL
;
335 char name
[IPMGMT_STRSIZE
];
337 boolean_t add_nvl
= B_FALSE
;
339 /* Parse db nvlist */
340 for (nvp
= nvlist_next_nvpair(db_nvl
, NULL
); nvp
!= NULL
;
341 nvp
= nvlist_next_nvpair(db_nvl
, nvp
)) {
342 if (nvpair_type(nvp
) == DATA_TYPE_NVLIST
)
343 (void) nvpair_value_nvlist(nvp
, &db_addr
);
344 else if (strcmp(nvpair_name(nvp
), IPADM_NVP_IFNAME
) == 0)
345 (void) nvpair_value_string(nvp
, &db_ifname
);
346 else if (strcmp(nvpair_name(nvp
), IPADM_NVP_AOBJNAME
) == 0)
347 (void) nvpair_value_string(nvp
, &db_aobjname
);
350 if (db_aobjname
== NULL
) /* Not an address */
353 /* Check for a match between the aobjnames or the interface name */
354 if (cbarg
->cb_aobjname
[0] != '\0') {
355 if (strcmp(cbarg
->cb_aobjname
, db_aobjname
) == 0)
357 } else if (cbarg
->cb_ifname
[0] != '\0') {
358 if (strcmp(cbarg
->cb_ifname
, db_ifname
) == 0)
365 (void) snprintf(name
, sizeof (name
), "%s_%d", db_ifname
,
367 *errp
= nvlist_add_nvlist(cbarg
->cb_onvl
, name
, db_nvl
);
375 * This function only gets called if a volatile filesystem version
376 * of the configuration file has been created. This only happens in the
377 * extremely rare case that a request has been made to update the configuration
378 * file at boottime while the root filesystem was read-only. This is
379 * really a rare occurrence now that we don't support UFS root filesystems
380 * any longer. This function will periodically attempt to write the
381 * configuration back to its location on the root filesystem. Success
382 * will indicate that the filesystem is no longer read-only.
386 ipmgmt_db_restore_thread(void *arg
)
392 (void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock
);
393 if (!ipmgmt_rdonly_root
)
395 err
= ipmgmt_cpfile(IPADM_VOL_DB_FILE
, IPADM_DB_FILE
, B_FALSE
);
397 ipmgmt_rdonly_root
= B_FALSE
;
400 (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock
);
402 (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock
);
407 * This function takes the appropriate lock, read or write, based on the
408 * `db_op' and then calls DB walker ipadm_rw_db(). The code is complicated
409 * by the fact that we are not always guaranteed to have a writable root
410 * filesystem since it is possible that we are reading or writing during
411 * bootime while the root filesystem is still read-only. This is, by far,
412 * the exception case. Normally, this function will be called when the
413 * root filesystem is writable. In the unusual case where this is not
414 * true, the configuration file is copied to the volatile file system
415 * and is updated there until the root filesystem becomes writable. At
416 * that time the file will be moved back to its proper location by
417 * ipmgmt_db_restore_thread().
420 ipmgmt_db_walk(db_wfunc_t
*db_walk_func
, void *db_warg
, ipadm_db_op_t db_op
)
428 writeop
= (db_op
!= IPADM_DB_READ
);
430 (void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock
);
431 mode
= IPADM_FILE_MODE
;
433 (void) pthread_rwlock_rdlock(&ipmgmt_dbconf_lock
);
438 * Did a previous write attempt fail? If so, don't even try to
439 * read/write to IPADM_DB_FILE.
441 if (!ipmgmt_rdonly_root
) {
442 err
= ipadm_rw_db(db_walk_func
, db_warg
, IPADM_DB_FILE
,
449 * If we haven't already copied the file to the volatile
450 * file system, do so. This should only happen on a failed
451 * writeop(i.e., we have acquired the write lock above).
453 if (access(IPADM_VOL_DB_FILE
, F_OK
) != 0) {
455 err
= ipmgmt_cpfile(IPADM_DB_FILE
, IPADM_VOL_DB_FILE
, B_TRUE
);
458 (void) pthread_attr_init(&attr
);
459 (void) pthread_attr_setdetachstate(&attr
,
460 PTHREAD_CREATE_DETACHED
);
461 (void) pthread_attr_setname_np(&attr
, "db_restore");
462 err
= pthread_create(&tid
, &attr
, ipmgmt_db_restore_thread
,
464 (void) pthread_attr_destroy(&attr
);
466 (void) unlink(IPADM_VOL_DB_FILE
);
469 ipmgmt_rdonly_root
= B_TRUE
;
473 * Read/write from the volatile copy.
475 err
= ipadm_rw_db(db_walk_func
, db_warg
, IPADM_VOL_DB_FILE
,
478 (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock
);
483 * Used to add an entry towards the end of DB. It just returns B_TRUE for
484 * every line of the DB. When we reach the end, ipadm_rw_db() adds the
489 ipmgmt_db_add(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
, int *errp
)
495 * This function is used to update or create an entry in DB. The nvlist_t,
496 * `in_nvl', represents the line we are looking for. Once we ensure the right
497 * line from DB, we update that entry.
500 ipmgmt_db_update(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
503 ipadm_dbwrite_cbarg_t
*cb
= arg
;
504 uint_t flags
= cb
->dbw_flags
;
505 nvlist_t
*in_nvl
= cb
->dbw_nvl
;
507 char *name
, *instrval
= NULL
, *dbstrval
= NULL
;
508 char pval
[MAXPROPVALLEN
];
511 if (!ipmgmt_nvlist_intersects(db_nvl
, in_nvl
))
514 for (nvp
= nvlist_next_nvpair(in_nvl
, NULL
); nvp
!= NULL
;
515 nvp
= nvlist_next_nvpair(in_nvl
, nvp
)) {
516 name
= nvpair_name(nvp
);
517 if (!IPADM_PRIV_NVP(name
) && nvlist_exists(db_nvl
, name
))
524 assert(nvpair_type(nvp
) == DATA_TYPE_STRING
);
526 if ((*errp
= nvpair_value_string(nvp
, &instrval
)) != 0)
530 * If IPMGMT_APPEND is set then we are dealing with multi-valued
531 * properties. We append to the entry from the db, with the new value.
533 if (flags
& IPMGMT_APPEND
) {
534 if ((*errp
= nvlist_lookup_string(db_nvl
, name
,
537 (void) snprintf(pval
, MAXPROPVALLEN
, "%s,%s", dbstrval
,
539 if ((*errp
= nvlist_add_string(db_nvl
, name
, pval
)) != 0)
542 /* case of in-line update of a db entry */
543 if ((*errp
= nvlist_add_string(db_nvl
, name
, instrval
)) != 0)
547 (void) memset(buf
, 0, buflen
);
548 if (ipadm_nvlist2str(db_nvl
, buf
, buflen
) == 0) {
549 /* buffer overflow */
553 /* we updated the DB entry, so do not continue */
558 * For the given `cbarg->cb_ifname' interface, retrieves any persistent
559 * interface information (used in 'ipadm show-if')
563 ipmgmt_db_getif(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
566 ipmgmt_getif_cbarg_t
*cbarg
= arg
;
567 char *ifname
= cbarg
->cb_ifname
;
569 ipadm_if_info_t
*ifp
= NULL
;
574 if (nvlist_lookup_string(db_nvl
, IPADM_NVP_FAMILY
, &afstr
) != 0 ||
575 nvlist_lookup_string(db_nvl
, IPADM_NVP_IFNAME
, &intf
) != 0 ||
576 (ifname
[0] != '\0' && strcmp(ifname
, intf
) != 0)) {
580 for (ifp
= cbarg
->cb_ifinfo
; ifp
!= NULL
; ifp
= ifp
->ifi_next
) {
581 if (strcmp(ifp
->ifi_name
, intf
) == 0)
585 ipadm_if_info_t
*new;
587 if ((new = calloc(1, sizeof (*new))) == NULL
) {
589 return (B_FALSE
); /* don't continue the walk */
591 new->ifi_next
= cbarg
->cb_ifinfo
;
592 cbarg
->cb_ifinfo
= new;
594 (void) strlcpy(ifp
->ifi_name
, intf
, sizeof (ifp
->ifi_name
));
598 ifp
->ifi_pflags
|= IFIF_IPV4
;
600 assert(af
== AF_INET6
);
601 ifp
->ifi_pflags
|= IFIF_IPV6
;
604 /* Terminate the walk if we found both v4 and v6 interfaces. */
605 if (ifname
[0] != '\0' && (ifp
->ifi_pflags
& IFIF_IPV4
) &&
606 (ifp
->ifi_pflags
& IFIF_IPV6
))
613 * Deletes those entries from the database for which interface name
614 * matches with the given `cbarg->cb_ifname'
618 ipmgmt_db_resetif(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
621 ipmgmt_if_cbarg_t
*cbarg
= arg
;
622 boolean_t isv6
= (cbarg
->cb_family
== AF_INET6
);
623 char *ifname
= cbarg
->cb_ifname
;
628 ipmgmt_aobjmap_t
*head
;
629 boolean_t aobjfound
= B_FALSE
;
633 if (!ipmgmt_nvlist_contains(db_nvl
, NULL
, ifname
, NULL
))
636 if (nvlist_lookup_string(db_nvl
, IPADM_NVP_FAMILY
, &afstr
) == 0) {
637 if (atoi(afstr
) == cbarg
->cb_family
)
642 /* Reset all the interface configurations for 'ifname' */
643 if (isv6
&& (nvlist_exists(db_nvl
, IPADM_NVP_IPV6ADDR
) ||
644 nvlist_exists(db_nvl
, IPADM_NVP_INTFID
))) {
648 (nvlist_exists(db_nvl
, IPADM_NVP_IPV4ADDR
) ||
649 nvlist_exists(db_nvl
, IPADM_NVP_DHCP
))) {
653 if (nvlist_lookup_string(db_nvl
, IPADM_NVP_AOBJNAME
, &aobjname
) == 0) {
655 * This must be an address property. Delete this
656 * line if there is a match in the address family.
658 head
= aobjmap
.aobjmap_head
;
659 while (head
!= NULL
) {
660 if (strcmp(head
->am_aobjname
, aobjname
) == 0) {
662 if (head
->am_family
== cbarg
->cb_family
)
665 head
= head
->am_next
;
668 * If aobjfound = B_FALSE, then this address is not
669 * available in active configuration. We should go ahead
677 * If we are removing both v4 and v6 interface, then we get rid of
678 * all the properties for that interface. On the other hand, if we
679 * are deleting only v4 instance of an interface, then we delete v4
682 if (nvlist_lookup_string(db_nvl
, IPADM_NVP_PROTONAME
, &modstr
) == 0) {
683 proto
= ipadm_str2proto(modstr
);
694 /* this should never be the case, today */
699 /* Not found a match yet. Continue processing the db */
702 /* delete the line from the db */
708 * Deletes those entries from the database for which address object name
709 * matches with the given `cbarg->cb_aobjname'
713 ipmgmt_db_resetaddr(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
716 ipmgmt_resetaddr_cbarg_t
*cbarg
= arg
;
717 char *aobjname
= cbarg
->cb_aobjname
;
720 if (!ipmgmt_nvlist_contains(db_nvl
, NULL
, NULL
, aobjname
))
723 /* delete the line from the db */
729 * Retrieves all interface props, including addresses, for given interface(s).
730 * `invl' contains the list of interfaces, for which information need to be
735 ipmgmt_db_initif(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
738 ipmgmt_initif_cbarg_t
*cbarg
= arg
;
739 nvlist_t
*onvl
= cbarg
->cb_onvl
;
740 nvlist_t
*invl
= cbarg
->cb_invl
;
741 sa_family_t in_af
= cbarg
->cb_family
;
745 if (nvlist_lookup_string(db_nvl
, IPADM_NVP_IFNAME
, &db_ifname
) == 0 &&
746 nvlist_exists(invl
, db_ifname
)) {
747 char name
[IPMGMT_STRSIZE
];
748 sa_family_t db_af
= in_af
;
752 if (in_af
!= AF_UNSPEC
) {
753 if (nvlist_lookup_string(db_nvl
, IPADM_NVP_PROTONAME
,
755 proto
= ipadm_str2proto(pstr
);
756 if (proto
== MOD_PROTO_IPV4
)
758 else if (proto
== MOD_PROTO_IPV6
)
763 if (nvlist_exists(db_nvl
, IPADM_NVP_IPV4ADDR
) ||
764 nvlist_exists(db_nvl
, IPADM_NVP_DHCP
))
770 if (in_af
== db_af
) {
771 (void) snprintf(name
, sizeof (name
), "%s_%d", db_ifname
,
773 *errp
= nvlist_add_nvlist(onvl
, name
, db_nvl
);
782 * helper function for ipmgmt_aobjmap_op(). Adds the node pointed by `nodep'
783 * into `aobjmap' structure.
786 i_ipmgmt_add_amnode(ipmgmt_aobjmap_t
*nodep
)
788 ipmgmt_aobjmap_t
*new, *head
;
790 head
= aobjmap
.aobjmap_head
;
791 if ((new = malloc(sizeof (ipmgmt_aobjmap_t
))) == NULL
)
796 /* Add the node at the beginning of the list */
798 aobjmap
.aobjmap_head
= new;
800 new->am_next
= aobjmap
.aobjmap_head
;
801 aobjmap
.aobjmap_head
= new;
807 * A recursive function to generate alphabetized number given a decimal number.
808 * Decimal 0 to 25 maps to 'a' to 'z' and then the counting continues with 'aa',
812 i_ipmgmt_num2priv_aobjname(uint32_t num
, char **cp
, char *endp
)
815 i_ipmgmt_num2priv_aobjname(num
/ 26 - 1, cp
, endp
);
817 *cp
[0] = 'a' + (num
% 26);
823 * This function generates an `aobjname', when required, and then does
824 * lookup-add. If `nodep->am_aobjname' is not an empty string, then it walks
825 * through the `aobjmap' to check if an address object with the same
826 * `nodep->am_aobjname' exists. If it exists, EEXIST is returned as duplicate
827 * `aobjname's are not allowed.
829 * If `nodep->am_aobjname' is an empty string then the daemon generates an
830 * `aobjname' using the `am_nextnum', which contains the next number to be
831 * used to generate `aobjname'. `am_nextnum' is converted to base26 using
832 * `a-z' alphabets in i_ipmgmt_num2priv_aobjname().
834 * `am_nextnum' will be 0 to begin with. Every time an address object that
835 * needs `aobjname' is added it's incremented by 1. So for the first address
836 * object on net0 the `am_aobjname' will be net0/_a and `am_nextnum' will be 1.
837 * For the second address object on that interface `am_aobjname' will be net0/_b
838 * and `am_nextnum' will incremented to 2.
841 i_ipmgmt_lookupadd_amnode(ipmgmt_aobjmap_t
*nodep
)
843 ipmgmt_aobjmap_t
*head
;
846 for (head
= aobjmap
.aobjmap_head
; head
!= NULL
; head
= head
->am_next
)
847 if (strcmp(head
->am_ifname
, nodep
->am_ifname
) == 0)
849 nextnum
= (head
== NULL
? 0 : head
->am_nextnum
);
852 * if `aobjname' is empty, then the daemon has to generate the
853 * next `aobjname' for the given interface and family.
855 if (nodep
->am_aobjname
[0] == '\0') {
856 char tmpstr
[IPADM_AOBJ_USTRSIZ
- 1]; /* 1 for leading '_' */
858 char *endp
= tmpstr
+ sizeof (tmpstr
);
860 i_ipmgmt_num2priv_aobjname(nextnum
, &cp
, endp
);
866 if (snprintf(nodep
->am_aobjname
, IPADM_AOBJSIZ
, "%s/_%s",
867 nodep
->am_ifname
, tmpstr
) >= IPADM_AOBJSIZ
) {
870 nodep
->am_nextnum
= ++nextnum
;
872 for (head
= aobjmap
.aobjmap_head
; head
!= NULL
;
873 head
= head
->am_next
) {
874 if (strcmp(head
->am_aobjname
, nodep
->am_aobjname
) == 0)
877 nodep
->am_nextnum
= nextnum
;
879 return (i_ipmgmt_add_amnode(nodep
));
883 * Performs following operations on the global `aobjmap' linked list.
884 * (a) ADDROBJ_ADD: add or update address object in `aobjmap'
885 * (b) ADDROBJ_DELETE: delete address object from `aobjmap'
886 * (c) ADDROBJ_LOOKUPADD: place a stub address object in `aobjmap'
887 * (d) ADDROBJ_SETLIFNUM: Sets the lifnum for an address object in `aobjmap'
890 ipmgmt_aobjmap_op(ipmgmt_aobjmap_t
*nodep
, uint32_t op
)
892 ipmgmt_aobjmap_t
*head
, *prev
, *matched
= NULL
;
893 boolean_t update
= B_TRUE
;
897 (void) pthread_rwlock_wrlock(&aobjmap
.aobjmap_rwlock
);
899 head
= aobjmap
.aobjmap_head
;
903 * check for stub nodes (added by ADDROBJ_LOOKUPADD) and
904 * update, else add the new node.
906 for (; head
!= NULL
; head
= head
->am_next
) {
908 * For IPv6, we need to distinguish between the
909 * linklocal and non-linklocal nodes
911 if (strcmp(head
->am_aobjname
,
912 nodep
->am_aobjname
) == 0 &&
913 (head
->am_atype
!= IPADM_ADDR_IPV6_ADDRCONF
||
914 head
->ipmgmt_am_linklocal
==
915 nodep
->ipmgmt_am_linklocal
))
920 /* update the node */
921 (void) strlcpy(head
->am_ifname
, nodep
->am_ifname
,
922 sizeof (head
->am_ifname
));
923 head
->am_lnum
= nodep
->am_lnum
;
924 head
->am_family
= nodep
->am_family
;
925 head
->am_flags
= nodep
->am_flags
;
926 head
->am_atype
= nodep
->am_atype
;
927 head
->am_atype_cache
= nodep
->am_atype_cache
;
929 for (head
= aobjmap
.aobjmap_head
; head
!= NULL
;
930 head
= head
->am_next
) {
931 if (strcmp(head
->am_ifname
,
932 nodep
->am_ifname
) == 0)
935 nodep
->am_nextnum
= (head
== NULL
? 0 :
937 err
= i_ipmgmt_add_amnode(nodep
);
939 db_op
= IPADM_DB_WRITE
;
943 while (head
!= NULL
) {
944 if (strcmp(head
->am_aobjname
,
945 nodep
->am_aobjname
) == 0) {
946 nodep
->am_atype
= head
->am_atype
;
948 * There could be multiple IPV6_ADDRCONF nodes,
949 * with same address object name, so check for
950 * logical number also.
952 if (head
->am_atype
!=
953 IPADM_ADDR_IPV6_ADDRCONF
||
954 nodep
->am_lnum
== head
->am_lnum
)
958 head
= head
->am_next
;
962 * If the address object is in both active and
963 * persistent configuration and the user is deleting it
964 * only from active configuration then mark this node
965 * for deletion by reseting IPMGMT_ACTIVE bit.
966 * With this the same address object name cannot
967 * be reused until it is permanently removed.
969 if (head
->am_flags
== (IPMGMT_ACTIVE
|IPMGMT_PERSIST
) &&
970 nodep
->am_flags
== IPMGMT_ACTIVE
) {
971 /* Update flags in the in-memory map. */
972 head
->am_flags
&= ~IPMGMT_ACTIVE
;
975 /* Update info in file. */
976 db_op
= IPADM_DB_WRITE
;
979 (void) strlcpy(nodep
->am_ifname
,
981 sizeof (nodep
->am_ifname
));
982 /* otherwise delete the node */
983 if (head
== aobjmap
.aobjmap_head
)
984 aobjmap
.aobjmap_head
= head
->am_next
;
986 prev
->am_next
= head
->am_next
;
988 db_op
= IPADM_DB_DELETE
;
994 case ADDROBJ_LOOKUPADD
:
995 err
= i_ipmgmt_lookupadd_amnode(nodep
);
998 case ADDROBJ_SETLIFNUM
:
1000 for (; head
!= NULL
; head
= head
->am_next
) {
1001 if (strcmp(head
->am_ifname
,
1002 nodep
->am_ifname
) == 0 &&
1003 head
->am_family
== nodep
->am_family
&&
1004 head
->am_lnum
== nodep
->am_lnum
) {
1008 if (strcmp(head
->am_aobjname
,
1009 nodep
->am_aobjname
) == 0) {
1015 if (matched
!= NULL
) {
1016 /* update the lifnum */
1017 matched
->am_lnum
= nodep
->am_lnum
;
1026 if (err
== 0 && update
)
1027 err
= ipmgmt_persist_aobjmap(nodep
, db_op
);
1029 (void) pthread_rwlock_unlock(&aobjmap
.aobjmap_rwlock
);
1035 * Given a node in `aobjmap', this function converts it into nvlist_t structure.
1036 * The content to be written to DB must be represented as nvlist_t.
1039 i_ipmgmt_node2nvl(nvlist_t
**nvl
, ipmgmt_aobjmap_t
*np
)
1042 char strval
[IPMGMT_STRSIZE
];
1045 if ((err
= nvlist_alloc(nvl
, NV_UNIQUE_NAME
, 0)) != 0)
1048 if ((err
= nvlist_add_string(*nvl
, IPADM_NVP_AOBJNAME
,
1049 np
->am_aobjname
)) != 0)
1052 if ((err
= nvlist_add_string(*nvl
, IPADM_NVP_IFNAME
,
1053 np
->am_ifname
)) != 0)
1056 (void) snprintf(strval
, IPMGMT_STRSIZE
, "%d", np
->am_lnum
);
1057 if ((err
= nvlist_add_string(*nvl
, IPADM_NVP_LIFNUM
, strval
)) != 0)
1060 (void) snprintf(strval
, IPMGMT_STRSIZE
, "%d", np
->am_family
);
1061 if ((err
= nvlist_add_string(*nvl
, IPADM_NVP_FAMILY
, strval
)) != 0)
1064 (void) snprintf(strval
, IPMGMT_STRSIZE
, "%d", np
->am_flags
);
1065 if ((err
= nvlist_add_string(*nvl
, FLAGS
, strval
)) != 0)
1068 (void) snprintf(strval
, IPMGMT_STRSIZE
, "%d", np
->am_atype
);
1069 if ((err
= nvlist_add_string(*nvl
, ATYPE
, strval
)) != 0)
1072 switch (np
->am_atype
) {
1073 case IPADM_ADDR_IPV6_ADDRCONF
: {
1074 struct sockaddr_in6
*in6
;
1076 in6
= &np
->ipmgmt_am_ifid
;
1077 if (np
->ipmgmt_am_linklocal
&&
1078 IN6_IS_ADDR_UNSPECIFIED(&in6
->sin6_addr
)) {
1079 if ((err
= nvlist_add_string(*nvl
,
1080 IPADM_NVP_IPNUMADDR
, "default")) != 0) {
1084 if (inet_ntop(AF_INET6
, &in6
->sin6_addr
, strval
,
1085 IPMGMT_STRSIZE
) == NULL
) {
1089 if ((err
= nvlist_add_string(*nvl
,
1090 IPADM_NVP_IPNUMADDR
, strval
)) != 0) {
1096 case IPADM_ADDR_DHCP
: {
1097 if (np
->ipmgmt_am_reqhost
&&
1098 *np
->ipmgmt_am_reqhost
!= '\0' &&
1099 (err
= nvlist_add_string(*nvl
, IPADM_NVP_REQHOST
,
1100 np
->ipmgmt_am_reqhost
)) != 0)
1105 if ((err
= nvlist_add_string(*nvl
, IPADM_NVP_IPNUMADDR
,
1117 * Read the aobjmap data store and build the in-memory representation
1118 * of the aobjmap. We don't need to hold any locks while building this as
1119 * we do this in very early stage of daemon coming up, even before the door
1124 ipmgmt_aobjmap_init(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
1127 nvpair_t
*nvp
= NULL
;
1128 char *name
, *strval
= NULL
;
1129 ipmgmt_aobjmap_t node
;
1130 struct sockaddr_in6
*in6
;
1133 node
.am_next
= NULL
;
1134 for (nvp
= nvlist_next_nvpair(db_nvl
, NULL
); nvp
!= NULL
;
1135 nvp
= nvlist_next_nvpair(db_nvl
, nvp
)) {
1136 name
= nvpair_name(nvp
);
1138 if ((*errp
= nvpair_value_string(nvp
, &strval
)) != 0)
1140 if (strcmp(IPADM_NVP_AOBJNAME
, name
) == 0) {
1141 (void) strlcpy(node
.am_aobjname
, strval
,
1142 sizeof (node
.am_aobjname
));
1143 } else if (strcmp(IPADM_NVP_IFNAME
, name
) == 0) {
1144 (void) strlcpy(node
.am_ifname
, strval
,
1145 sizeof (node
.am_ifname
));
1146 } else if (strcmp(IPADM_NVP_LIFNUM
, name
) == 0) {
1147 node
.am_lnum
= atoi(strval
);
1148 } else if (strcmp(IPADM_NVP_FAMILY
, name
) == 0) {
1149 node
.am_family
= (sa_family_t
)atoi(strval
);
1150 } else if (strcmp(FLAGS
, name
) == 0) {
1151 node
.am_flags
= atoi(strval
);
1152 } else if (strcmp(ATYPE
, name
) == 0) {
1153 node
.am_atype
= (ipadm_addr_type_t
)atoi(strval
);
1154 } else if (strcmp(IPADM_NVP_IPNUMADDR
, name
) == 0) {
1155 if (node
.am_atype
== IPADM_ADDR_IPV6_ADDRCONF
) {
1156 in6
= &node
.ipmgmt_am_ifid
;
1157 if (strcmp(strval
, "default") == 0) {
1159 sizeof (node
.ipmgmt_am_ifid
));
1160 node
.ipmgmt_am_linklocal
= B_TRUE
;
1162 (void) inet_pton(AF_INET6
, strval
,
1164 if (IN6_IS_ADDR_UNSPECIFIED(
1166 node
.ipmgmt_am_linklocal
=
1173 /* we have all the information we need, add the node */
1174 *errp
= i_ipmgmt_add_amnode(&node
);
1180 * Updates an entry from the temporary cache file, which matches the given
1181 * address object name.
1185 ipmgmt_update_aobjmap(void *arg
, nvlist_t
*db_nvl
, char *buf
,
1186 size_t buflen
, int *errp
)
1188 ipadm_dbwrite_cbarg_t
*cb
= arg
;
1189 nvlist_t
*in_nvl
= cb
->dbw_nvl
;
1190 uint32_t flags
= cb
->dbw_flags
;
1191 char *db_lifnumstr
= NULL
, *in_lifnumstr
= NULL
;
1194 if (!ipmgmt_nvlist_intersects(db_nvl
, in_nvl
))
1197 if (flags
& IPMGMT_ATYPE_V6ACONF
) {
1198 if (nvlist_lookup_string(db_nvl
, IPADM_NVP_LIFNUM
,
1199 &db_lifnumstr
) != 0 ||
1200 nvlist_lookup_string(in_nvl
, IPADM_NVP_LIFNUM
,
1201 &in_lifnumstr
) != 0 ||
1202 (atoi(db_lifnumstr
) != -1 && atoi(in_lifnumstr
) != -1 &&
1203 strcmp(db_lifnumstr
, in_lifnumstr
) != 0))
1207 /* we found the match */
1208 (void) memset(buf
, 0, buflen
);
1209 if (ipadm_nvlist2str(in_nvl
, buf
, buflen
) == 0) {
1210 /* buffer overflow */
1214 /* stop the walker */
1219 * Deletes an entry from the temporary cache file, which matches the given
1220 * address object name.
1224 ipmgmt_delete_aobjmap(void *arg
, nvlist_t
*db_nvl
, char *buf
,
1225 size_t buflen
, int *errp
)
1227 ipmgmt_aobjmap_t
*nodep
= arg
;
1228 char *db_lifnumstr
= NULL
;
1231 if (!ipmgmt_nvlist_match(db_nvl
, NULL
, nodep
->am_ifname
,
1232 nodep
->am_aobjname
))
1235 if (nodep
->am_atype
== IPADM_ADDR_IPV6_ADDRCONF
) {
1236 if (nvlist_lookup_string(db_nvl
, IPADM_NVP_LIFNUM
,
1237 &db_lifnumstr
) != 0 || atoi(db_lifnumstr
) != nodep
->am_lnum
)
1241 /* we found the match, delete the line from the db */
1244 /* stop the walker */
1249 * Adds or deletes aobjmap node information into a temporary cache file.
1252 ipmgmt_persist_aobjmap(ipmgmt_aobjmap_t
*nodep
, ipadm_db_op_t op
)
1255 ipadm_dbwrite_cbarg_t cb
;
1256 nvlist_t
*nvl
= NULL
;
1258 if (op
== IPADM_DB_WRITE
) {
1259 if ((err
= i_ipmgmt_node2nvl(&nvl
, nodep
)) != 0)
1262 if (nodep
->am_atype
== IPADM_ADDR_IPV6_ADDRCONF
)
1263 cb
.dbw_flags
= IPMGMT_ATYPE_V6ACONF
;
1267 err
= ipadm_rw_db(ipmgmt_update_aobjmap
, &cb
,
1268 ADDROBJ_MAPPING_DB_FILE
, IPADM_FILE_MODE
, IPADM_DB_WRITE
);
1271 assert(op
== IPADM_DB_DELETE
);
1273 err
= ipadm_rw_db(ipmgmt_delete_aobjmap
, nodep
,
1274 ADDROBJ_MAPPING_DB_FILE
, IPADM_FILE_MODE
, IPADM_DB_DELETE
);
1280 * upgrades the ipadm data-store. It renames all the old private protocol
1281 * property names which start with leading protocol names to begin with
1282 * IPADM_PRIV_PROP_PREFIX.
1286 ipmgmt_db_upgrade(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
1290 char *name
, *pname
= NULL
, *protostr
= NULL
, *pval
= NULL
;
1291 uint_t proto
, nproto
;
1292 char nname
[IPMGMT_STRSIZE
], tmpstr
[IPMGMT_STRSIZE
];
1296 * We are interested in lines which contain protocol properties. We
1297 * walk through other lines in the DB.
1299 if (nvlist_exists(db_nvl
, IPADM_NVP_IFNAME
) ||
1300 nvlist_exists(db_nvl
, IPADM_NVP_AOBJNAME
)) {
1303 assert(nvlist_exists(db_nvl
, IPADM_NVP_PROTONAME
));
1306 * extract the propname from the `db_nvl' and also extract the
1307 * protocol from the `db_nvl'.
1309 for (nvp
= nvlist_next_nvpair(db_nvl
, NULL
); nvp
!= NULL
;
1310 nvp
= nvlist_next_nvpair(db_nvl
, nvp
)) {
1311 name
= nvpair_name(nvp
);
1312 if (strcmp(name
, IPADM_NVP_PROTONAME
) == 0) {
1313 if (nvpair_value_string(nvp
, &protostr
) != 0)
1316 assert(!IPADM_PRIV_NVP(name
));
1318 if (nvpair_value_string(nvp
, &pval
) != 0)
1323 /* if the private property is in the right format return */
1324 if (strncmp(pname
, IPADM_PERSIST_PRIVPROP_PREFIX
,
1325 strlen(IPADM_PERSIST_PRIVPROP_PREFIX
)) == 0) {
1328 /* if it's a public property move onto the next property */
1329 nproto
= proto
= ipadm_str2proto(protostr
);
1330 if (ipadm_legacy2new_propname(pname
, nname
, sizeof (nname
),
1335 /* replace the old protocol with new protocol, if required */
1336 if (nproto
!= proto
) {
1337 protostr
= ipadm_proto2str(nproto
);
1338 if (nvlist_add_string(db_nvl
, IPADM_NVP_PROTONAME
,
1344 /* replace the old property name with new property name, if required */
1345 /* add the prefix to property name */
1346 (void) snprintf(tmpstr
, sizeof (tmpstr
), "_%s", nname
);
1347 if (nvlist_add_string(db_nvl
, tmpstr
, pval
) != 0 ||
1348 nvlist_remove(db_nvl
, pname
, DATA_TYPE_STRING
) != 0) {
1351 (void) memset(buf
, 0, buflen
);
1352 if (ipadm_nvlist2str(db_nvl
, buf
, buflen
) == 0) {
1353 /* buffer overflow */
1360 * Called during boot.
1362 * Walk through the DB and apply all the global module properties. We plow
1363 * through the DB even if we fail to apply property.
1367 ipmgmt_db_init(void *cbarg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
1370 ipadm_handle_t iph
= cbarg
;
1371 nvpair_t
*nvp
, *pnvp
;
1372 char *strval
= NULL
, *name
, *mod
= NULL
, *pname
;
1373 char tmpstr
[IPMGMT_STRSIZE
];
1377 * We could have used nvl_exists() directly, however we need several
1378 * calls to it and each call traverses the list. Since this codepath
1379 * is exercised during boot, let's traverse the list ourselves and do
1380 * the necessary checks.
1382 for (nvp
= nvlist_next_nvpair(db_nvl
, NULL
); nvp
!= NULL
;
1383 nvp
= nvlist_next_nvpair(db_nvl
, nvp
)) {
1384 name
= nvpair_name(nvp
);
1385 if (IPADM_PRIV_NVP(name
)) {
1386 if (strcmp(name
, IPADM_NVP_IFNAME
) == 0 ||
1387 strcmp(name
, IPADM_NVP_AOBJNAME
) == 0)
1389 else if (strcmp(name
, IPADM_NVP_PROTONAME
) == 0 &&
1390 nvpair_value_string(nvp
, &mod
) != 0)
1393 /* possible a property */
1398 /* if we are here than we found a global property */
1399 assert(mod
!= NULL
);
1400 assert(nvpair_type(pnvp
) == DATA_TYPE_STRING
);
1402 proto
= ipadm_str2proto(mod
);
1403 name
= nvpair_name(pnvp
);
1404 if (nvpair_value_string(pnvp
, &strval
) == 0) {
1405 if (strncmp(name
, IPADM_PERSIST_PRIVPROP_PREFIX
,
1406 strlen(IPADM_PERSIST_PRIVPROP_PREFIX
)) == 0) {
1407 /* private protocol property */
1409 } else if (ipadm_legacy2new_propname(name
, tmpstr
,
1410 sizeof (tmpstr
), &proto
) == 0) {
1415 if (ipadm_set_prop(iph
, pname
, strval
, proto
,
1416 IPADM_OPT_ACTIVE
) != IPADM_SUCCESS
) {
1417 ipmgmt_log(LOG_WARNING
, "Failed to reapply property %s",
1425 /* initialize global module properties */
1429 ipadm_handle_t iph
= NULL
;
1431 if (ipadm_open(&iph
, IPH_INIT
) != IPADM_SUCCESS
) {
1432 ipmgmt_log(LOG_WARNING
, "Could not reapply any of the "
1433 "persisted protocol properties");
1436 /* ipmgmt_db_init() logs warnings if there are any issues */
1437 (void) ipmgmt_db_walk(ipmgmt_db_init
, iph
, IPADM_DB_READ
);
1442 ipmgmt_release_scf_resources(scf_resources_t
*res
)
1444 scf_entry_destroy(res
->sr_ent
);
1445 scf_transaction_destroy(res
->sr_tx
);
1446 scf_value_destroy(res
->sr_val
);
1447 scf_property_destroy(res
->sr_prop
);
1448 scf_pg_destroy(res
->sr_pg
);
1449 scf_instance_destroy(res
->sr_inst
);
1450 (void) scf_handle_unbind(res
->sr_handle
);
1451 scf_handle_destroy(res
->sr_handle
);
1455 * It creates the necessary SCF handles and binds the given `fmri' to an
1456 * instance. These resources are required for retrieving property value,
1457 * creating property groups and modifying property values.
1460 ipmgmt_create_scf_resources(const char *fmri
, scf_resources_t
*res
)
1464 res
->sr_inst
= NULL
;
1466 res
->sr_prop
= NULL
;
1469 if ((res
->sr_handle
= scf_handle_create(SCF_VERSION
)) == NULL
)
1472 if (scf_handle_bind(res
->sr_handle
) != 0) {
1473 scf_handle_destroy(res
->sr_handle
);
1476 if ((res
->sr_inst
= scf_instance_create(res
->sr_handle
)) == NULL
)
1478 if (scf_handle_decode_fmri(res
->sr_handle
, fmri
, NULL
, NULL
,
1479 res
->sr_inst
, NULL
, NULL
, SCF_DECODE_FMRI_REQUIRE_INSTANCE
) != 0) {
1482 /* we will create the rest of the resources on demand */
1486 ipmgmt_log(LOG_WARNING
, "failed to create scf resources: %s",
1487 scf_strerror(scf_error()));
1488 ipmgmt_release_scf_resources(res
);
1493 * persists the `pval' for a given property `pname' in SCF. The only supported
1494 * SCF property types are INTEGER and ASTRING.
1497 ipmgmt_set_scfprop_value(scf_resources_t
*res
, const char *pname
, void *pval
,
1503 if ((res
->sr_val
= scf_value_create(res
->sr_handle
)) == NULL
)
1506 case SCF_TYPE_INTEGER
:
1507 scf_value_set_integer(res
->sr_val
, *(int64_t *)pval
);
1509 case SCF_TYPE_ASTRING
:
1510 if (scf_value_set_astring(res
->sr_val
, (char *)pval
) != 0) {
1511 ipmgmt_log(LOG_WARNING
, "Error setting string value %s "
1512 "for property %s: %s", pval
, pname
,
1513 scf_strerror(scf_error()));
1521 if ((res
->sr_tx
= scf_transaction_create(res
->sr_handle
)) == NULL
)
1523 if ((res
->sr_ent
= scf_entry_create(res
->sr_handle
)) == NULL
)
1525 if ((res
->sr_prop
= scf_property_create(res
->sr_handle
)) == NULL
)
1529 new = (scf_pg_get_property(res
->sr_pg
, pname
, res
->sr_prop
) != 0);
1530 if (scf_transaction_start(res
->sr_tx
, res
->sr_pg
) == -1)
1533 if (scf_transaction_property_new(res
->sr_tx
, res
->sr_ent
,
1534 pname
, ptype
) == -1) {
1538 if (scf_transaction_property_change(res
->sr_tx
, res
->sr_ent
,
1539 pname
, ptype
) == -1) {
1544 if (scf_entry_add_value(res
->sr_ent
, res
->sr_val
) != 0)
1547 result
= scf_transaction_commit(res
->sr_tx
);
1549 scf_transaction_reset(res
->sr_tx
);
1550 if (scf_pg_update(res
->sr_pg
) == -1) {
1560 ipmgmt_log(LOG_WARNING
, "failed to save the data in SCF: %s",
1561 scf_strerror(scf_error()));
1566 * Given a `pgname'/`pname', it retrieves the value based on `ptype' and
1567 * places it in `pval'.
1570 ipmgmt_get_scfprop(scf_resources_t
*res
, const char *pgname
, const char *pname
,
1571 void *pval
, scf_type_t ptype
)
1574 scf_simple_prop_t
*prop
;
1576 prop
= scf_simple_prop_get(res
->sr_handle
, IPMGMTD_FMRI
, pgname
, pname
);
1577 numvals
= scf_simple_prop_numvalues(prop
);
1581 case SCF_TYPE_INTEGER
:
1582 *(int64_t **)pval
= scf_simple_prop_next_integer(prop
);
1584 case SCF_TYPE_ASTRING
:
1585 *(char **)pval
= scf_simple_prop_next_astring(prop
);
1589 scf_simple_prop_free(prop
);
1594 * It stores the `pval' for given `pgname'/`pname' property group in SCF.
1597 ipmgmt_set_scfprop(scf_resources_t
*res
, const char *pgname
, const char *pname
,
1598 void *pval
, scf_type_t ptype
)
1602 if ((res
->sr_pg
= scf_pg_create(res
->sr_handle
)) == NULL
) {
1603 ipmgmt_log(LOG_WARNING
, "failed to create property group: %s",
1604 scf_strerror(scf_error()));
1608 if (scf_instance_add_pg(res
->sr_inst
, pgname
, SCF_GROUP_APPLICATION
,
1609 0, res
->sr_pg
) != 0) {
1610 if ((err
= scf_error()) != SCF_ERROR_EXISTS
) {
1611 ipmgmt_log(LOG_WARNING
,
1612 "Error adding property group '%s/%s': %s",
1613 pgname
, pname
, scf_strerror(err
));
1617 * if the property group already exists, then we get the
1618 * composed view of the property group for the given instance.
1620 if (scf_instance_get_pg_composed(res
->sr_inst
, NULL
, pgname
,
1622 ipmgmt_log(LOG_WARNING
, "Error getting composed view "
1623 "of the property group '%s/%s': %s", pgname
, pname
,
1624 scf_strerror(scf_error()));
1629 return (ipmgmt_set_scfprop_value(res
, pname
, pval
, ptype
));
1633 * Returns B_TRUE, if the non-global zone is being booted for the first time
1634 * after being installed. This is required to setup the ipadm data-store for
1635 * the first boot of the non-global zone. Please see, PSARC 2010/166,
1638 * Note that, this API cannot be used to determine first boot post image-update.
1639 * 'pkg image-update' clones the current BE and the existing value of
1640 * ipmgmtd/first_boot_done will be carried forward and obviously it will be set
1644 ipmgmt_ngz_firstboot_postinstall()
1646 scf_resources_t res
;
1647 boolean_t bval
= B_TRUE
;
1650 /* we always err on the side of caution */
1651 if (ipmgmt_create_scf_resources(IPMGMTD_FMRI
, &res
) != 0)
1654 if (ipmgmt_get_scfprop(&res
, IPMGMTD_APP_PG
, IPMGMTD_PROP_FBD
, &strval
,
1655 SCF_TYPE_ASTRING
) > 0) {
1656 bval
= (strcmp(strval
, IPMGMTD_TRUESTR
) == 0 ?
1660 * IPMGMTD_PROP_FBD does not exist in the SCF. Lets create it.
1661 * Since we err on the side of caution, we ignore the return
1662 * error and return B_TRUE.
1664 (void) ipmgmt_set_scfprop(&res
, IPMGMTD_APP_PG
,
1665 IPMGMTD_PROP_FBD
, IPMGMTD_TRUESTR
, SCF_TYPE_ASTRING
);
1667 ipmgmt_release_scf_resources(&res
);
1672 * Returns B_TRUE, if the data-store needs upgrade otherwise returns B_FALSE.
1673 * Today we have to take care of, one case of, upgrading from version 0 to
1674 * version 1, so we will use boolean_t as means to decide if upgrade is needed
1675 * or not. Further, the upcoming projects might completely move the flatfile
1676 * data-store into SCF and hence we shall keep this interface simple.
1679 ipmgmt_needs_upgrade(scf_resources_t
*res
)
1681 boolean_t bval
= B_TRUE
;
1684 if (ipmgmt_get_scfprop(res
, IPMGMTD_APP_PG
, IPMGMTD_PROP_DBVER
,
1685 &verp
, SCF_TYPE_INTEGER
) > 0) {
1686 if (*verp
== IPADM_DB_VERSION
)
1690 * 'datastore_version' doesn't exist. Which means that we need to
1691 * upgrade the datastore. We will create 'datastore_version' and set
1692 * the version value to IPADM_DB_VERSION, after we upgrade the file.
1698 * This is called after the successful upgrade of the local data-store. With
1699 * the data-store upgraded to recent version we don't have to do anything on
1700 * subsequent reboots.
1703 ipmgmt_update_dbver(scf_resources_t
*res
)
1705 int64_t version
= IPADM_DB_VERSION
;
1707 (void) ipmgmt_set_scfprop(res
, IPMGMTD_APP_PG
,
1708 IPMGMTD_PROP_DBVER
, &version
, SCF_TYPE_INTEGER
);