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.
28 * Contains DB walker functions, which are of type `db_wfunc_t';
30 * typedef boolean_t db_wfunc_t(void *cbarg, nvlist_t *db_nvl, char *buf,
31 * size_t bufsize, int *errp);
33 * ipadm_rw_db() walks through the data store, one line at a time and calls
34 * these call back functions with:
35 * `cbarg' - callback argument
36 * `db_nvl' - representing a line from DB in nvlist_t form
37 * `buf' - character buffer to hold modified line
38 * `bufsize'- size of the buffer
39 * `errp' - captures any error inside the walker function.
41 * All the 'write' callback functions modify `db_nvl' based on `cbarg' and
42 * copy string representation of `db_nvl' (using ipadm_nvlist2str()) into `buf'.
43 * To delete a line from the DB, buf[0] is set to `\0'. Inside ipadm_rw_db(),
44 * the modified `buf' is written back into DB.
46 * All the 'read' callback functions, retrieve the information from the DB, by
47 * reading `db_nvl' and then populate the `cbarg'.
54 #include <sys/types.h>
55 #include <sys/socket.h>
56 #include <netinet/in.h>
57 #include <arpa/inet.h>
59 #include "ipmgmt_impl.h"
61 /* SCF related property group names and property names */
62 #define IPMGMTD_APP_PG "ipmgmtd"
63 #define IPMGMTD_PROP_FBD "first_boot_done"
64 #define IPMGMTD_PROP_DBVER "datastore_version"
65 #define IPMGMTD_TRUESTR "true"
67 #define ATYPE "_atype" /* name of the address type nvpair */
68 #define FLAGS "_flags" /* name of the flags nvpair */
71 * flag used by ipmgmt_persist_aobjmap() to indicate address type is
72 * IPADM_ADDR_IPV6_ADDRCONF.
74 #define IPMGMT_ATYPE_V6ACONF 0x1
76 extern pthread_rwlock_t ipmgmt_dbconf_lock
;
78 /* signifies whether volatile copy of data store is in use */
79 static boolean_t ipmgmt_rdonly_root
= B_FALSE
;
82 * Checks if the database nvl, `db_nvl' contains and matches ALL of the passed
83 * in private nvpairs `proto', `ifname' & `aobjname'.
86 ipmgmt_nvlist_match(nvlist_t
*db_nvl
, const char *proto
, const char *ifname
,
89 char *db_proto
= NULL
, *db_ifname
= NULL
;
90 char *db_aobjname
= NULL
;
94 /* walk through db_nvl and retrieve all its private nvpairs */
95 for (nvp
= nvlist_next_nvpair(db_nvl
, NULL
); nvp
!= NULL
;
96 nvp
= nvlist_next_nvpair(db_nvl
, nvp
)) {
97 name
= nvpair_name(nvp
);
98 if (strcmp(IPADM_NVP_PROTONAME
, name
) == 0)
99 (void) nvpair_value_string(nvp
, &db_proto
);
100 else if (strcmp(IPADM_NVP_IFNAME
, name
) == 0)
101 (void) nvpair_value_string(nvp
, &db_ifname
);
102 else if (strcmp(IPADM_NVP_AOBJNAME
, name
) == 0)
103 (void) nvpair_value_string(nvp
, &db_aobjname
);
106 if (proto
!= NULL
&& proto
[0] == '\0')
108 if (ifname
!= NULL
&& ifname
[0] == '\0')
110 if (aobjname
!= NULL
&& aobjname
[0] == '\0')
113 if ((proto
== NULL
&& db_proto
!= NULL
) ||
114 (proto
!= NULL
&& db_proto
== NULL
) ||
115 (proto
!= NULL
&& db_proto
!= NULL
&&
116 strcmp(proto
, db_proto
) != 0)) {
117 /* no intersection - different protocols. */
120 if ((ifname
== NULL
&& db_ifname
!= NULL
) ||
121 (ifname
!= NULL
&& db_ifname
== NULL
) ||
122 (ifname
!= NULL
&& db_ifname
!= NULL
&&
123 strcmp(ifname
, db_ifname
) != 0)) {
124 /* no intersection - different interfaces. */
127 if ((aobjname
== NULL
&& db_aobjname
!= NULL
) ||
128 (aobjname
!= NULL
&& db_aobjname
== NULL
) ||
129 (aobjname
!= NULL
&& db_aobjname
!= NULL
&&
130 strcmp(aobjname
, db_aobjname
) != 0)) {
131 /* no intersection - different address objects */
139 * Checks if the database nvl, `db_nvl' and the input nvl, `in_nvl' intersects.
142 ipmgmt_nvlist_intersects(nvlist_t
*db_nvl
, nvlist_t
*in_nvl
)
146 char *proto
= NULL
, *ifname
= NULL
, *aobjname
= NULL
;
148 /* walk through in_nvl and retrieve all its private nvpairs */
149 for (nvp
= nvlist_next_nvpair(in_nvl
, NULL
); nvp
!= NULL
;
150 nvp
= nvlist_next_nvpair(in_nvl
, nvp
)) {
151 name
= nvpair_name(nvp
);
152 if (strcmp(IPADM_NVP_PROTONAME
, name
) == 0)
153 (void) nvpair_value_string(nvp
, &proto
);
154 else if (strcmp(IPADM_NVP_IFNAME
, name
) == 0)
155 (void) nvpair_value_string(nvp
, &ifname
);
156 else if (strcmp(IPADM_NVP_AOBJNAME
, name
) == 0)
157 (void) nvpair_value_string(nvp
, &aobjname
);
160 return (ipmgmt_nvlist_match(db_nvl
, proto
, ifname
, aobjname
));
164 * Checks if the database nvl, `db_nvl', contains and matches ANY of the passed
165 * in private nvpairs `proto', `ifname' & `aobjname'.
168 ipmgmt_nvlist_contains(nvlist_t
*db_nvl
, const char *proto
,
169 const char *ifname
, char *aobjname
)
171 char *db_ifname
= NULL
, *db_proto
= NULL
;
172 char *db_aobjname
= NULL
;
176 /* walk through db_nvl and retrieve all private nvpairs */
177 for (nvp
= nvlist_next_nvpair(db_nvl
, NULL
); nvp
!= NULL
;
178 nvp
= nvlist_next_nvpair(db_nvl
, nvp
)) {
179 name
= nvpair_name(nvp
);
180 if (strcmp(IPADM_NVP_PROTONAME
, name
) == 0)
181 (void) nvpair_value_string(nvp
, &db_proto
);
182 else if (strcmp(IPADM_NVP_IFNAME
, name
) == 0)
183 (void) nvpair_value_string(nvp
, &db_ifname
);
184 else if (strcmp(IPADM_NVP_AOBJNAME
, name
) == 0)
185 (void) nvpair_value_string(nvp
, &db_aobjname
);
188 if (proto
!= NULL
&& proto
[0] != '\0') {
189 if ((db_proto
== NULL
|| strcmp(proto
, db_proto
) != 0))
192 if (ifname
!= NULL
&& ifname
[0] != '\0') {
193 if ((db_ifname
== NULL
|| strcmp(ifname
, db_ifname
) != 0))
196 if (aobjname
!= NULL
&& aobjname
[0] != '\0') {
197 if ((db_aobjname
== NULL
|| strcmp(aobjname
, db_aobjname
) != 0))
205 * Retrieves the property value from the DB. The property whose value is to be
206 * retrieved is in `pargp->ia_pname'.
210 ipmgmt_db_getprop(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
213 ipmgmt_prop_arg_t
*pargp
= arg
;
214 boolean_t cont
= B_TRUE
;
220 if (!ipmgmt_nvlist_match(db_nvl
, pargp
->ia_module
,
221 pargp
->ia_ifname
, pargp
->ia_aobjname
))
224 if ((err
= nvlist_lookup_string(db_nvl
, pargp
->ia_pname
,
226 (void) strlcpy(pargp
->ia_pval
, pval
, sizeof (pargp
->ia_pval
));
228 * We have retrieved what we are looking for.
242 * Removes the property value from the DB. The property whose value is to be
243 * removed is in `pargp->ia_pname'.
247 ipmgmt_db_resetprop(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
250 ipmgmt_prop_arg_t
*pargp
= arg
;
253 if (!ipmgmt_nvlist_match(db_nvl
, pargp
->ia_module
,
254 pargp
->ia_ifname
, pargp
->ia_aobjname
))
257 if (!nvlist_exists(db_nvl
, pargp
->ia_pname
))
261 * We found the property in the DB. If IPMGMT_REMOVE is not set then
262 * delete the entry from the db. If it is set, then the property is a
263 * multi-valued property so just remove the specified values from DB.
265 if (pargp
->ia_flags
& IPMGMT_REMOVE
) {
267 char *inpval
= pargp
->ia_pval
;
268 char pval
[MAXPROPVALLEN
];
271 *errp
= nvlist_lookup_string(db_nvl
, pargp
->ia_pname
, &dbpval
);
276 * multi-valued properties are represented as comma separated
277 * values. Use string tokenizer functions to split them and
278 * search for the value to be removed.
280 bzero(pval
, sizeof (pval
));
281 if ((val
= strtok_r(dbpval
, ",", &lasts
)) != NULL
) {
282 if (strcmp(val
, inpval
) != 0)
283 (void) strlcat(pval
, val
, MAXPROPVALLEN
);
284 while ((val
= strtok_r(NULL
, ",", &lasts
)) != NULL
) {
285 if (strcmp(val
, inpval
) != 0) {
287 (void) strlcat(pval
, ",",
289 (void) strlcat(pval
, val
,
294 if (strcmp(dbpval
, inpval
) != 0)
300 *errp
= nvlist_add_string(db_nvl
, pargp
->ia_pname
, pval
);
304 (void) memset(buf
, 0, buflen
);
305 if (ipadm_nvlist2str(db_nvl
, buf
, buflen
) == 0) {
306 /* buffer overflow */
313 /* stop the search */
318 * Input arguments can have IPADM_NVP_AOBJNAME or IPADM_NVP_IFNAME. A match is
319 * found, when one of the following occurs first.
320 * - the input aobjname matches the db aobjname. Return the db address.
321 * - the input interface matches the db interface. Return all the
322 * matching db lines with addresses.
326 ipmgmt_db_getaddr(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
329 ipmgmt_getaddr_cbarg_t
*cbarg
= arg
;
330 char *db_aobjname
= NULL
;
331 char *db_ifname
= NULL
;
332 nvlist_t
*db_addr
= NULL
;
333 char name
[IPMGMT_STRSIZE
];
335 boolean_t add_nvl
= B_FALSE
;
337 /* Parse db nvlist */
338 for (nvp
= nvlist_next_nvpair(db_nvl
, NULL
); nvp
!= NULL
;
339 nvp
= nvlist_next_nvpair(db_nvl
, nvp
)) {
340 if (nvpair_type(nvp
) == DATA_TYPE_NVLIST
)
341 (void) nvpair_value_nvlist(nvp
, &db_addr
);
342 else if (strcmp(nvpair_name(nvp
), IPADM_NVP_IFNAME
) == 0)
343 (void) nvpair_value_string(nvp
, &db_ifname
);
344 else if (strcmp(nvpair_name(nvp
), IPADM_NVP_AOBJNAME
) == 0)
345 (void) nvpair_value_string(nvp
, &db_aobjname
);
348 if (db_aobjname
== NULL
) /* Not an address */
351 /* Check for a match between the aobjnames or the interface name */
352 if (cbarg
->cb_aobjname
[0] != '\0') {
353 if (strcmp(cbarg
->cb_aobjname
, db_aobjname
) == 0)
355 } else if (cbarg
->cb_ifname
[0] != '\0') {
356 if (strcmp(cbarg
->cb_ifname
, db_ifname
) == 0)
363 (void) snprintf(name
, sizeof (name
), "%s_%d", db_ifname
,
365 *errp
= nvlist_add_nvlist(cbarg
->cb_onvl
, name
, db_nvl
);
373 * This function only gets called if a volatile filesystem version
374 * of the configuration file has been created. This only happens in the
375 * extremely rare case that a request has been made to update the configuration
376 * file at boottime while the root filesystem was read-only. This is
377 * really a rare occurrence now that we don't support UFS root filesystems
378 * any longer. This function will periodically attempt to write the
379 * configuration back to its location on the root filesystem. Success
380 * will indicate that the filesystem is no longer read-only.
384 ipmgmt_db_restore_thread(void *arg
)
390 (void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock
);
391 if (!ipmgmt_rdonly_root
)
393 err
= ipmgmt_cpfile(IPADM_VOL_DB_FILE
, IPADM_DB_FILE
, B_FALSE
);
395 ipmgmt_rdonly_root
= B_FALSE
;
398 (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock
);
400 (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock
);
405 * This function takes the appropriate lock, read or write, based on the
406 * `db_op' and then calls DB walker ipadm_rw_db(). The code is complicated
407 * by the fact that we are not always guaranteed to have a writable root
408 * filesystem since it is possible that we are reading or writing during
409 * bootime while the root filesystem is still read-only. This is, by far,
410 * the exception case. Normally, this function will be called when the
411 * root filesystem is writable. In the unusual case where this is not
412 * true, the configuration file is copied to the volatile file system
413 * and is updated there until the root filesystem becomes writable. At
414 * that time the file will be moved back to its proper location by
415 * ipmgmt_db_restore_thread().
418 ipmgmt_db_walk(db_wfunc_t
*db_walk_func
, void *db_warg
, ipadm_db_op_t db_op
)
426 writeop
= (db_op
!= IPADM_DB_READ
);
428 (void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock
);
429 mode
= IPADM_FILE_MODE
;
431 (void) pthread_rwlock_rdlock(&ipmgmt_dbconf_lock
);
436 * Did a previous write attempt fail? If so, don't even try to
437 * read/write to IPADM_DB_FILE.
439 if (!ipmgmt_rdonly_root
) {
440 err
= ipadm_rw_db(db_walk_func
, db_warg
, IPADM_DB_FILE
,
447 * If we haven't already copied the file to the volatile
448 * file system, do so. This should only happen on a failed
449 * writeop(i.e., we have acquired the write lock above).
451 if (access(IPADM_VOL_DB_FILE
, F_OK
) != 0) {
453 err
= ipmgmt_cpfile(IPADM_DB_FILE
, IPADM_VOL_DB_FILE
, B_TRUE
);
456 (void) pthread_attr_init(&attr
);
457 (void) pthread_attr_setdetachstate(&attr
,
458 PTHREAD_CREATE_DETACHED
);
459 err
= pthread_create(&tid
, &attr
, ipmgmt_db_restore_thread
,
461 (void) pthread_attr_destroy(&attr
);
463 (void) unlink(IPADM_VOL_DB_FILE
);
466 ipmgmt_rdonly_root
= B_TRUE
;
470 * Read/write from the volatile copy.
472 err
= ipadm_rw_db(db_walk_func
, db_warg
, IPADM_VOL_DB_FILE
,
475 (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock
);
480 * Used to add an entry towards the end of DB. It just returns B_TRUE for
481 * every line of the DB. When we reach the end, ipadm_rw_db() adds the
486 ipmgmt_db_add(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
, int *errp
)
492 * This function is used to update or create an entry in DB. The nvlist_t,
493 * `in_nvl', represents the line we are looking for. Once we ensure the right
494 * line from DB, we update that entry.
497 ipmgmt_db_update(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
500 ipadm_dbwrite_cbarg_t
*cb
= arg
;
501 uint_t flags
= cb
->dbw_flags
;
502 nvlist_t
*in_nvl
= cb
->dbw_nvl
;
504 char *name
, *instrval
= NULL
, *dbstrval
= NULL
;
505 char pval
[MAXPROPVALLEN
];
508 if (!ipmgmt_nvlist_intersects(db_nvl
, in_nvl
))
511 for (nvp
= nvlist_next_nvpair(in_nvl
, NULL
); nvp
!= NULL
;
512 nvp
= nvlist_next_nvpair(in_nvl
, nvp
)) {
513 name
= nvpair_name(nvp
);
514 if (!IPADM_PRIV_NVP(name
) && nvlist_exists(db_nvl
, name
))
521 assert(nvpair_type(nvp
) == DATA_TYPE_STRING
);
523 if ((*errp
= nvpair_value_string(nvp
, &instrval
)) != 0)
527 * If IPMGMT_APPEND is set then we are dealing with multi-valued
528 * properties. We append to the entry from the db, with the new value.
530 if (flags
& IPMGMT_APPEND
) {
531 if ((*errp
= nvlist_lookup_string(db_nvl
, name
,
534 (void) snprintf(pval
, MAXPROPVALLEN
, "%s,%s", dbstrval
,
536 if ((*errp
= nvlist_add_string(db_nvl
, name
, pval
)) != 0)
539 /* case of in-line update of a db entry */
540 if ((*errp
= nvlist_add_string(db_nvl
, name
, instrval
)) != 0)
544 (void) memset(buf
, 0, buflen
);
545 if (ipadm_nvlist2str(db_nvl
, buf
, buflen
) == 0) {
546 /* buffer overflow */
550 /* we updated the DB entry, so do not continue */
555 * For the given `cbarg->cb_ifname' interface, retrieves any persistent
556 * interface information (used in 'ipadm show-if')
560 ipmgmt_db_getif(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
563 ipmgmt_getif_cbarg_t
*cbarg
= arg
;
564 char *ifname
= cbarg
->cb_ifname
;
566 ipadm_if_info_t
*ifp
= NULL
;
571 if (nvlist_lookup_string(db_nvl
, IPADM_NVP_FAMILY
, &afstr
) != 0 ||
572 nvlist_lookup_string(db_nvl
, IPADM_NVP_IFNAME
, &intf
) != 0 ||
573 (ifname
[0] != '\0' && strcmp(ifname
, intf
) != 0)) {
577 for (ifp
= cbarg
->cb_ifinfo
; ifp
!= NULL
; ifp
= ifp
->ifi_next
) {
578 if (strcmp(ifp
->ifi_name
, intf
) == 0)
582 ipadm_if_info_t
*new;
584 if ((new = calloc(1, sizeof (*new))) == NULL
) {
586 return (B_FALSE
); /* don't continue the walk */
588 new->ifi_next
= cbarg
->cb_ifinfo
;
589 cbarg
->cb_ifinfo
= new;
591 (void) strlcpy(ifp
->ifi_name
, intf
, sizeof (ifp
->ifi_name
));
595 ifp
->ifi_pflags
|= IFIF_IPV4
;
597 assert(af
== AF_INET6
);
598 ifp
->ifi_pflags
|= IFIF_IPV6
;
601 /* Terminate the walk if we found both v4 and v6 interfaces. */
602 if (ifname
[0] != '\0' && (ifp
->ifi_pflags
& IFIF_IPV4
) &&
603 (ifp
->ifi_pflags
& IFIF_IPV6
))
610 * Deletes those entries from the database for which interface name
611 * matches with the given `cbarg->cb_ifname'
615 ipmgmt_db_resetif(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
618 ipmgmt_if_cbarg_t
*cbarg
= arg
;
619 boolean_t isv6
= (cbarg
->cb_family
== AF_INET6
);
620 char *ifname
= cbarg
->cb_ifname
;
625 ipmgmt_aobjmap_t
*head
;
626 boolean_t aobjfound
= B_FALSE
;
630 if (!ipmgmt_nvlist_contains(db_nvl
, NULL
, ifname
, NULL
))
633 if (nvlist_lookup_string(db_nvl
, IPADM_NVP_FAMILY
, &afstr
) == 0) {
634 if (atoi(afstr
) == cbarg
->cb_family
)
639 /* Reset all the interface configurations for 'ifname' */
640 if (isv6
&& (nvlist_exists(db_nvl
, IPADM_NVP_IPV6ADDR
) ||
641 nvlist_exists(db_nvl
, IPADM_NVP_INTFID
))) {
645 (nvlist_exists(db_nvl
, IPADM_NVP_IPV4ADDR
) ||
646 nvlist_exists(db_nvl
, IPADM_NVP_DHCP
))) {
650 if (nvlist_lookup_string(db_nvl
, IPADM_NVP_AOBJNAME
, &aobjname
) == 0) {
652 * This must be an address property. Delete this
653 * line if there is a match in the address family.
655 head
= aobjmap
.aobjmap_head
;
656 while (head
!= NULL
) {
657 if (strcmp(head
->am_aobjname
, aobjname
) == 0) {
659 if (head
->am_family
== cbarg
->cb_family
)
662 head
= head
->am_next
;
665 * If aobjfound = B_FALSE, then this address is not
666 * available in active configuration. We should go ahead
674 * If we are removing both v4 and v6 interface, then we get rid of
675 * all the properties for that interface. On the other hand, if we
676 * are deleting only v4 instance of an interface, then we delete v4
679 if (nvlist_lookup_string(db_nvl
, IPADM_NVP_PROTONAME
, &modstr
) == 0) {
680 proto
= ipadm_str2proto(modstr
);
691 /* this should never be the case, today */
696 /* Not found a match yet. Continue processing the db */
699 /* delete the line from the db */
705 * Deletes those entries from the database for which address object name
706 * matches with the given `cbarg->cb_aobjname'
710 ipmgmt_db_resetaddr(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
713 ipmgmt_resetaddr_cbarg_t
*cbarg
= arg
;
714 char *aobjname
= cbarg
->cb_aobjname
;
717 if (!ipmgmt_nvlist_contains(db_nvl
, NULL
, NULL
, aobjname
))
720 /* delete the line from the db */
726 * Retrieves all interface props, including addresses, for given interface(s).
727 * `invl' contains the list of interfaces, for which information need to be
732 ipmgmt_db_initif(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
735 ipmgmt_initif_cbarg_t
*cbarg
= arg
;
736 nvlist_t
*onvl
= cbarg
->cb_onvl
;
737 nvlist_t
*invl
= cbarg
->cb_invl
;
738 sa_family_t in_af
= cbarg
->cb_family
;
742 if (nvlist_lookup_string(db_nvl
, IPADM_NVP_IFNAME
, &db_ifname
) == 0 &&
743 nvlist_exists(invl
, db_ifname
)) {
744 char name
[IPMGMT_STRSIZE
];
745 sa_family_t db_af
= in_af
;
749 if (in_af
!= AF_UNSPEC
) {
750 if (nvlist_lookup_string(db_nvl
, IPADM_NVP_PROTONAME
,
752 proto
= ipadm_str2proto(pstr
);
753 if (proto
== MOD_PROTO_IPV4
)
755 else if (proto
== MOD_PROTO_IPV6
)
760 if (nvlist_exists(db_nvl
, IPADM_NVP_IPV4ADDR
) ||
761 nvlist_exists(db_nvl
, IPADM_NVP_DHCP
))
767 if (in_af
== db_af
) {
768 (void) snprintf(name
, sizeof (name
), "%s_%d", db_ifname
,
770 *errp
= nvlist_add_nvlist(onvl
, name
, db_nvl
);
779 * helper function for ipmgmt_aobjmap_op(). Adds the node pointed by `nodep'
780 * into `aobjmap' structure.
783 i_ipmgmt_add_amnode(ipmgmt_aobjmap_t
*nodep
)
785 ipmgmt_aobjmap_t
*new, *head
;
787 head
= aobjmap
.aobjmap_head
;
788 if ((new = malloc(sizeof (ipmgmt_aobjmap_t
))) == NULL
)
793 /* Add the node at the beginning of the list */
795 aobjmap
.aobjmap_head
= new;
797 new->am_next
= aobjmap
.aobjmap_head
;
798 aobjmap
.aobjmap_head
= new;
804 * A recursive function to generate alphabetized number given a decimal number.
805 * Decimal 0 to 25 maps to 'a' to 'z' and then the counting continues with 'aa',
809 i_ipmgmt_num2priv_aobjname(uint32_t num
, char **cp
, char *endp
)
812 i_ipmgmt_num2priv_aobjname(num
/ 26 - 1, cp
, endp
);
814 *cp
[0] = 'a' + (num
% 26);
820 * This function generates an `aobjname', when required, and then does
821 * lookup-add. If `nodep->am_aobjname' is not an empty string, then it walks
822 * through the `aobjmap' to check if an address object with the same
823 * `nodep->am_aobjname' exists. If it exists, EEXIST is returned as duplicate
824 * `aobjname's are not allowed.
826 * If `nodep->am_aobjname' is an empty string then the daemon generates an
827 * `aobjname' using the `am_nextnum', which contains the next number to be
828 * used to generate `aobjname'. `am_nextnum' is converted to base26 using
829 * `a-z' alphabets in i_ipmgmt_num2priv_aobjname().
831 * `am_nextnum' will be 0 to begin with. Every time an address object that
832 * needs `aobjname' is added it's incremented by 1. So for the first address
833 * object on net0 the `am_aobjname' will be net0/_a and `am_nextnum' will be 1.
834 * For the second address object on that interface `am_aobjname' will be net0/_b
835 * and `am_nextnum' will incremented to 2.
838 i_ipmgmt_lookupadd_amnode(ipmgmt_aobjmap_t
*nodep
)
840 ipmgmt_aobjmap_t
*head
;
843 for (head
= aobjmap
.aobjmap_head
; head
!= NULL
; head
= head
->am_next
)
844 if (strcmp(head
->am_ifname
, nodep
->am_ifname
) == 0)
846 nextnum
= (head
== NULL
? 0 : head
->am_nextnum
);
849 * if `aobjname' is empty, then the daemon has to generate the
850 * next `aobjname' for the given interface and family.
852 if (nodep
->am_aobjname
[0] == '\0') {
853 char tmpstr
[IPADM_AOBJ_USTRSIZ
- 1]; /* 1 for leading '_' */
855 char *endp
= tmpstr
+ sizeof (tmpstr
);
857 i_ipmgmt_num2priv_aobjname(nextnum
, &cp
, endp
);
863 if (snprintf(nodep
->am_aobjname
, IPADM_AOBJSIZ
, "%s/_%s",
864 nodep
->am_ifname
, tmpstr
) >= IPADM_AOBJSIZ
) {
867 nodep
->am_nextnum
= ++nextnum
;
869 for (head
= aobjmap
.aobjmap_head
; head
!= NULL
;
870 head
= head
->am_next
) {
871 if (strcmp(head
->am_aobjname
, nodep
->am_aobjname
) == 0)
874 nodep
->am_nextnum
= nextnum
;
876 return (i_ipmgmt_add_amnode(nodep
));
880 * Performs following operations on the global `aobjmap' linked list.
881 * (a) ADDROBJ_ADD: add or update address object in `aobjmap'
882 * (b) ADDROBJ_DELETE: delete address object from `aobjmap'
883 * (c) ADDROBJ_LOOKUPADD: place a stub address object in `aobjmap'
884 * (d) ADDROBJ_SETLIFNUM: Sets the lifnum for an address object in `aobjmap'
887 ipmgmt_aobjmap_op(ipmgmt_aobjmap_t
*nodep
, uint32_t op
)
889 ipmgmt_aobjmap_t
*head
, *prev
, *matched
= NULL
;
890 boolean_t update
= B_TRUE
;
894 (void) pthread_rwlock_wrlock(&aobjmap
.aobjmap_rwlock
);
896 head
= aobjmap
.aobjmap_head
;
900 * check for stub nodes (added by ADDROBJ_LOOKUPADD) and
901 * update, else add the new node.
903 for (; head
!= NULL
; head
= head
->am_next
) {
905 * For IPv6, we need to distinguish between the
906 * linklocal and non-linklocal nodes
908 if (strcmp(head
->am_aobjname
,
909 nodep
->am_aobjname
) == 0 &&
910 (head
->am_atype
!= IPADM_ADDR_IPV6_ADDRCONF
||
911 head
->am_linklocal
== nodep
->am_linklocal
))
916 /* update the node */
917 (void) strlcpy(head
->am_ifname
, nodep
->am_ifname
,
918 sizeof (head
->am_ifname
));
919 head
->am_lnum
= nodep
->am_lnum
;
920 head
->am_family
= nodep
->am_family
;
921 head
->am_flags
= nodep
->am_flags
;
922 head
->am_atype
= nodep
->am_atype
;
923 if (head
->am_atype
== IPADM_ADDR_IPV6_ADDRCONF
) {
924 head
->am_ifid
= nodep
->am_ifid
;
925 head
->am_linklocal
= nodep
->am_linklocal
;
928 for (head
= aobjmap
.aobjmap_head
; head
!= NULL
;
929 head
= head
->am_next
) {
930 if (strcmp(head
->am_ifname
,
931 nodep
->am_ifname
) == 0)
934 nodep
->am_nextnum
= (head
== NULL
? 0 :
936 err
= i_ipmgmt_add_amnode(nodep
);
938 db_op
= IPADM_DB_WRITE
;
942 while (head
!= NULL
) {
943 if (strcmp(head
->am_aobjname
,
944 nodep
->am_aobjname
) == 0) {
945 nodep
->am_atype
= head
->am_atype
;
947 * There could be multiple IPV6_ADDRCONF nodes,
948 * with same address object name, so check for
949 * logical number also.
951 if (head
->am_atype
!=
952 IPADM_ADDR_IPV6_ADDRCONF
||
953 nodep
->am_lnum
== head
->am_lnum
)
957 head
= head
->am_next
;
961 * If the address object is in both active and
962 * persistent configuration and the user is deleting it
963 * only from active configuration then mark this node
964 * for deletion by reseting IPMGMT_ACTIVE bit.
965 * With this the same address object name cannot
966 * be reused until it is permanently removed.
968 if (head
->am_flags
== (IPMGMT_ACTIVE
|IPMGMT_PERSIST
) &&
969 nodep
->am_flags
== IPMGMT_ACTIVE
) {
970 /* Update flags in the in-memory map. */
971 head
->am_flags
&= ~IPMGMT_ACTIVE
;
974 /* Update info in file. */
975 db_op
= IPADM_DB_WRITE
;
978 (void) strlcpy(nodep
->am_ifname
,
980 sizeof (nodep
->am_ifname
));
981 /* otherwise delete the node */
982 if (head
== aobjmap
.aobjmap_head
)
983 aobjmap
.aobjmap_head
= head
->am_next
;
985 prev
->am_next
= head
->am_next
;
987 db_op
= IPADM_DB_DELETE
;
993 case ADDROBJ_LOOKUPADD
:
994 err
= i_ipmgmt_lookupadd_amnode(nodep
);
997 case ADDROBJ_SETLIFNUM
:
999 for (; head
!= NULL
; head
= head
->am_next
) {
1000 if (strcmp(head
->am_ifname
,
1001 nodep
->am_ifname
) == 0 &&
1002 head
->am_family
== nodep
->am_family
&&
1003 head
->am_lnum
== nodep
->am_lnum
) {
1007 if (strcmp(head
->am_aobjname
,
1008 nodep
->am_aobjname
) == 0) {
1014 if (matched
!= NULL
) {
1015 /* update the lifnum */
1016 matched
->am_lnum
= nodep
->am_lnum
;
1025 if (err
== 0 && update
)
1026 err
= ipmgmt_persist_aobjmap(nodep
, db_op
);
1028 (void) pthread_rwlock_unlock(&aobjmap
.aobjmap_rwlock
);
1034 * Given a node in `aobjmap', this function converts it into nvlist_t structure.
1035 * The content to be written to DB must be represented as nvlist_t.
1038 i_ipmgmt_node2nvl(nvlist_t
**nvl
, ipmgmt_aobjmap_t
*np
)
1041 char strval
[IPMGMT_STRSIZE
];
1044 if ((err
= nvlist_alloc(nvl
, NV_UNIQUE_NAME
, 0)) != 0)
1047 if ((err
= nvlist_add_string(*nvl
, IPADM_NVP_AOBJNAME
,
1048 np
->am_aobjname
)) != 0)
1051 if ((err
= nvlist_add_string(*nvl
, IPADM_NVP_IFNAME
,
1052 np
->am_ifname
)) != 0)
1055 (void) snprintf(strval
, IPMGMT_STRSIZE
, "%d", np
->am_lnum
);
1056 if ((err
= nvlist_add_string(*nvl
, IPADM_NVP_LIFNUM
, strval
)) != 0)
1059 (void) snprintf(strval
, IPMGMT_STRSIZE
, "%d", np
->am_family
);
1060 if ((err
= nvlist_add_string(*nvl
, IPADM_NVP_FAMILY
, strval
)) != 0)
1063 (void) snprintf(strval
, IPMGMT_STRSIZE
, "%d", np
->am_flags
);
1064 if ((err
= nvlist_add_string(*nvl
, FLAGS
, strval
)) != 0)
1067 (void) snprintf(strval
, IPMGMT_STRSIZE
, "%d", np
->am_atype
);
1068 if ((err
= nvlist_add_string(*nvl
, ATYPE
, strval
)) != 0)
1071 if (np
->am_atype
== IPADM_ADDR_IPV6_ADDRCONF
) {
1072 struct sockaddr_in6
*in6
;
1074 in6
= (struct sockaddr_in6
*)&np
->am_ifid
;
1075 if (np
->am_linklocal
&&
1076 IN6_IS_ADDR_UNSPECIFIED(&in6
->sin6_addr
)) {
1077 if ((err
= nvlist_add_string(*nvl
, IPADM_NVP_IPNUMADDR
,
1081 if (inet_ntop(AF_INET6
, &in6
->sin6_addr
, strval
,
1082 IPMGMT_STRSIZE
) == NULL
) {
1086 if ((err
= nvlist_add_string(*nvl
, IPADM_NVP_IPNUMADDR
,
1091 if ((err
= nvlist_add_string(*nvl
, IPADM_NVP_IPNUMADDR
,
1102 * Read the aobjmap data store and build the in-memory representation
1103 * of the aobjmap. We don't need to hold any locks while building this as
1104 * we do this in very early stage of daemon coming up, even before the door
1109 ipmgmt_aobjmap_init(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
1112 nvpair_t
*nvp
= NULL
;
1113 char *name
, *strval
= NULL
;
1114 ipmgmt_aobjmap_t node
;
1115 struct sockaddr_in6
*in6
;
1118 node
.am_next
= NULL
;
1119 for (nvp
= nvlist_next_nvpair(db_nvl
, NULL
); nvp
!= NULL
;
1120 nvp
= nvlist_next_nvpair(db_nvl
, nvp
)) {
1121 name
= nvpair_name(nvp
);
1123 if ((*errp
= nvpair_value_string(nvp
, &strval
)) != 0)
1125 if (strcmp(IPADM_NVP_AOBJNAME
, name
) == 0) {
1126 (void) strlcpy(node
.am_aobjname
, strval
,
1127 sizeof (node
.am_aobjname
));
1128 } else if (strcmp(IPADM_NVP_IFNAME
, name
) == 0) {
1129 (void) strlcpy(node
.am_ifname
, strval
,
1130 sizeof (node
.am_ifname
));
1131 } else if (strcmp(IPADM_NVP_LIFNUM
, name
) == 0) {
1132 node
.am_lnum
= atoi(strval
);
1133 } else if (strcmp(IPADM_NVP_FAMILY
, name
) == 0) {
1134 node
.am_family
= (sa_family_t
)atoi(strval
);
1135 } else if (strcmp(FLAGS
, name
) == 0) {
1136 node
.am_flags
= atoi(strval
);
1137 } else if (strcmp(ATYPE
, name
) == 0) {
1138 node
.am_atype
= (ipadm_addr_type_t
)atoi(strval
);
1139 } else if (strcmp(IPADM_NVP_IPNUMADDR
, name
) == 0) {
1140 if (node
.am_atype
== IPADM_ADDR_IPV6_ADDRCONF
) {
1141 in6
= (struct sockaddr_in6
*)&node
.am_ifid
;
1142 if (strcmp(strval
, "default") == 0) {
1143 bzero(in6
, sizeof (node
.am_ifid
));
1144 node
.am_linklocal
= B_TRUE
;
1146 (void) inet_pton(AF_INET6
, strval
,
1148 if (IN6_IS_ADDR_UNSPECIFIED(
1150 node
.am_linklocal
= B_TRUE
;
1156 /* we have all the information we need, add the node */
1157 *errp
= i_ipmgmt_add_amnode(&node
);
1163 * Updates an entry from the temporary cache file, which matches the given
1164 * address object name.
1168 ipmgmt_update_aobjmap(void *arg
, nvlist_t
*db_nvl
, char *buf
,
1169 size_t buflen
, int *errp
)
1171 ipadm_dbwrite_cbarg_t
*cb
= arg
;
1172 nvlist_t
*in_nvl
= cb
->dbw_nvl
;
1173 uint32_t flags
= cb
->dbw_flags
;
1174 char *db_lifnumstr
= NULL
, *in_lifnumstr
= NULL
;
1177 if (!ipmgmt_nvlist_intersects(db_nvl
, in_nvl
))
1180 if (flags
& IPMGMT_ATYPE_V6ACONF
) {
1181 if (nvlist_lookup_string(db_nvl
, IPADM_NVP_LIFNUM
,
1182 &db_lifnumstr
) != 0 ||
1183 nvlist_lookup_string(in_nvl
, IPADM_NVP_LIFNUM
,
1184 &in_lifnumstr
) != 0 ||
1185 (atoi(db_lifnumstr
) != -1 && atoi(in_lifnumstr
) != -1 &&
1186 strcmp(db_lifnumstr
, in_lifnumstr
) != 0))
1190 /* we found the match */
1191 (void) memset(buf
, 0, buflen
);
1192 if (ipadm_nvlist2str(in_nvl
, buf
, buflen
) == 0) {
1193 /* buffer overflow */
1197 /* stop the walker */
1202 * Deletes an entry from the temporary cache file, which matches the given
1203 * address object name.
1207 ipmgmt_delete_aobjmap(void *arg
, nvlist_t
*db_nvl
, char *buf
,
1208 size_t buflen
, int *errp
)
1210 ipmgmt_aobjmap_t
*nodep
= arg
;
1211 char *db_lifnumstr
= NULL
;
1214 if (!ipmgmt_nvlist_match(db_nvl
, NULL
, nodep
->am_ifname
,
1215 nodep
->am_aobjname
))
1218 if (nodep
->am_atype
== IPADM_ADDR_IPV6_ADDRCONF
) {
1219 if (nvlist_lookup_string(db_nvl
, IPADM_NVP_LIFNUM
,
1220 &db_lifnumstr
) != 0 || atoi(db_lifnumstr
) != nodep
->am_lnum
)
1224 /* we found the match, delete the line from the db */
1227 /* stop the walker */
1232 * Adds or deletes aobjmap node information into a temporary cache file.
1235 ipmgmt_persist_aobjmap(ipmgmt_aobjmap_t
*nodep
, ipadm_db_op_t op
)
1238 ipadm_dbwrite_cbarg_t cb
;
1239 nvlist_t
*nvl
= NULL
;
1241 if (op
== IPADM_DB_WRITE
) {
1242 if ((err
= i_ipmgmt_node2nvl(&nvl
, nodep
)) != 0)
1245 if (nodep
->am_atype
== IPADM_ADDR_IPV6_ADDRCONF
)
1246 cb
.dbw_flags
= IPMGMT_ATYPE_V6ACONF
;
1250 err
= ipadm_rw_db(ipmgmt_update_aobjmap
, &cb
,
1251 ADDROBJ_MAPPING_DB_FILE
, IPADM_FILE_MODE
, IPADM_DB_WRITE
);
1254 assert(op
== IPADM_DB_DELETE
);
1256 err
= ipadm_rw_db(ipmgmt_delete_aobjmap
, nodep
,
1257 ADDROBJ_MAPPING_DB_FILE
, IPADM_FILE_MODE
, IPADM_DB_DELETE
);
1263 * upgrades the ipadm data-store. It renames all the old private protocol
1264 * property names which start with leading protocol names to begin with
1265 * IPADM_PRIV_PROP_PREFIX.
1269 ipmgmt_db_upgrade(void *arg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
1273 char *name
, *pname
= NULL
, *protostr
= NULL
, *pval
= NULL
;
1274 uint_t proto
, nproto
;
1275 char nname
[IPMGMT_STRSIZE
], tmpstr
[IPMGMT_STRSIZE
];
1279 * We are interested in lines which contain protocol properties. We
1280 * walk through other lines in the DB.
1282 if (nvlist_exists(db_nvl
, IPADM_NVP_IFNAME
) ||
1283 nvlist_exists(db_nvl
, IPADM_NVP_AOBJNAME
)) {
1286 assert(nvlist_exists(db_nvl
, IPADM_NVP_PROTONAME
));
1289 * extract the propname from the `db_nvl' and also extract the
1290 * protocol from the `db_nvl'.
1292 for (nvp
= nvlist_next_nvpair(db_nvl
, NULL
); nvp
!= NULL
;
1293 nvp
= nvlist_next_nvpair(db_nvl
, nvp
)) {
1294 name
= nvpair_name(nvp
);
1295 if (strcmp(name
, IPADM_NVP_PROTONAME
) == 0) {
1296 if (nvpair_value_string(nvp
, &protostr
) != 0)
1299 assert(!IPADM_PRIV_NVP(name
));
1301 if (nvpair_value_string(nvp
, &pval
) != 0)
1306 /* if the private property is in the right format return */
1307 if (strncmp(pname
, IPADM_PERSIST_PRIVPROP_PREFIX
,
1308 strlen(IPADM_PERSIST_PRIVPROP_PREFIX
)) == 0) {
1311 /* if it's a public property move onto the next property */
1312 nproto
= proto
= ipadm_str2proto(protostr
);
1313 if (ipadm_legacy2new_propname(pname
, nname
, sizeof (nname
),
1318 /* replace the old protocol with new protocol, if required */
1319 if (nproto
!= proto
) {
1320 protostr
= ipadm_proto2str(nproto
);
1321 if (nvlist_add_string(db_nvl
, IPADM_NVP_PROTONAME
,
1327 /* replace the old property name with new property name, if required */
1328 /* add the prefix to property name */
1329 (void) snprintf(tmpstr
, sizeof (tmpstr
), "_%s", nname
);
1330 if (nvlist_add_string(db_nvl
, tmpstr
, pval
) != 0 ||
1331 nvlist_remove(db_nvl
, pname
, DATA_TYPE_STRING
) != 0) {
1334 (void) memset(buf
, 0, buflen
);
1335 if (ipadm_nvlist2str(db_nvl
, buf
, buflen
) == 0) {
1336 /* buffer overflow */
1343 * Called during boot.
1345 * Walk through the DB and apply all the global module properties. We plow
1346 * through the DB even if we fail to apply property.
1350 ipmgmt_db_init(void *cbarg
, nvlist_t
*db_nvl
, char *buf
, size_t buflen
,
1353 ipadm_handle_t iph
= cbarg
;
1354 nvpair_t
*nvp
, *pnvp
;
1355 char *strval
= NULL
, *name
, *mod
= NULL
, *pname
;
1356 char tmpstr
[IPMGMT_STRSIZE
];
1360 * We could have used nvl_exists() directly, however we need several
1361 * calls to it and each call traverses the list. Since this codepath
1362 * is exercised during boot, let's traverse the list ourselves and do
1363 * the necessary checks.
1365 for (nvp
= nvlist_next_nvpair(db_nvl
, NULL
); nvp
!= NULL
;
1366 nvp
= nvlist_next_nvpair(db_nvl
, nvp
)) {
1367 name
= nvpair_name(nvp
);
1368 if (IPADM_PRIV_NVP(name
)) {
1369 if (strcmp(name
, IPADM_NVP_IFNAME
) == 0 ||
1370 strcmp(name
, IPADM_NVP_AOBJNAME
) == 0)
1372 else if (strcmp(name
, IPADM_NVP_PROTONAME
) == 0 &&
1373 nvpair_value_string(nvp
, &mod
) != 0)
1376 /* possible a property */
1381 /* if we are here than we found a global property */
1382 assert(mod
!= NULL
);
1383 assert(nvpair_type(pnvp
) == DATA_TYPE_STRING
);
1385 proto
= ipadm_str2proto(mod
);
1386 name
= nvpair_name(pnvp
);
1387 if (nvpair_value_string(pnvp
, &strval
) == 0) {
1388 if (strncmp(name
, IPADM_PERSIST_PRIVPROP_PREFIX
,
1389 strlen(IPADM_PERSIST_PRIVPROP_PREFIX
)) == 0) {
1390 /* private protocol property */
1392 } else if (ipadm_legacy2new_propname(name
, tmpstr
,
1393 sizeof (tmpstr
), &proto
) == 0) {
1398 if (ipadm_set_prop(iph
, pname
, strval
, proto
,
1399 IPADM_OPT_ACTIVE
) != IPADM_SUCCESS
) {
1400 ipmgmt_log(LOG_WARNING
, "Failed to reapply property %s",
1408 /* initialize global module properties */
1412 ipadm_handle_t iph
= NULL
;
1414 if (ipadm_open(&iph
, IPH_INIT
) != IPADM_SUCCESS
) {
1415 ipmgmt_log(LOG_WARNING
, "Could not reapply any of the "
1416 "persisted protocol properties");
1419 /* ipmgmt_db_init() logs warnings if there are any issues */
1420 (void) ipmgmt_db_walk(ipmgmt_db_init
, iph
, IPADM_DB_READ
);
1425 ipmgmt_release_scf_resources(scf_resources_t
*res
)
1427 scf_entry_destroy(res
->sr_ent
);
1428 scf_transaction_destroy(res
->sr_tx
);
1429 scf_value_destroy(res
->sr_val
);
1430 scf_property_destroy(res
->sr_prop
);
1431 scf_pg_destroy(res
->sr_pg
);
1432 scf_instance_destroy(res
->sr_inst
);
1433 (void) scf_handle_unbind(res
->sr_handle
);
1434 scf_handle_destroy(res
->sr_handle
);
1438 * It creates the necessary SCF handles and binds the given `fmri' to an
1439 * instance. These resources are required for retrieving property value,
1440 * creating property groups and modifying property values.
1443 ipmgmt_create_scf_resources(const char *fmri
, scf_resources_t
*res
)
1447 res
->sr_inst
= NULL
;
1449 res
->sr_prop
= NULL
;
1452 if ((res
->sr_handle
= scf_handle_create(SCF_VERSION
)) == NULL
)
1455 if (scf_handle_bind(res
->sr_handle
) != 0) {
1456 scf_handle_destroy(res
->sr_handle
);
1459 if ((res
->sr_inst
= scf_instance_create(res
->sr_handle
)) == NULL
)
1461 if (scf_handle_decode_fmri(res
->sr_handle
, fmri
, NULL
, NULL
,
1462 res
->sr_inst
, NULL
, NULL
, SCF_DECODE_FMRI_REQUIRE_INSTANCE
) != 0) {
1465 /* we will create the rest of the resources on demand */
1469 ipmgmt_log(LOG_WARNING
, "failed to create scf resources: %s",
1470 scf_strerror(scf_error()));
1471 ipmgmt_release_scf_resources(res
);
1476 * persists the `pval' for a given property `pname' in SCF. The only supported
1477 * SCF property types are INTEGER and ASTRING.
1480 ipmgmt_set_scfprop_value(scf_resources_t
*res
, const char *pname
, void *pval
,
1486 if ((res
->sr_val
= scf_value_create(res
->sr_handle
)) == NULL
)
1489 case SCF_TYPE_INTEGER
:
1490 scf_value_set_integer(res
->sr_val
, *(int64_t *)pval
);
1492 case SCF_TYPE_ASTRING
:
1493 if (scf_value_set_astring(res
->sr_val
, (char *)pval
) != 0) {
1494 ipmgmt_log(LOG_WARNING
, "Error setting string value %s "
1495 "for property %s: %s", pval
, pname
,
1496 scf_strerror(scf_error()));
1504 if ((res
->sr_tx
= scf_transaction_create(res
->sr_handle
)) == NULL
)
1506 if ((res
->sr_ent
= scf_entry_create(res
->sr_handle
)) == NULL
)
1508 if ((res
->sr_prop
= scf_property_create(res
->sr_handle
)) == NULL
)
1512 new = (scf_pg_get_property(res
->sr_pg
, pname
, res
->sr_prop
) != 0);
1513 if (scf_transaction_start(res
->sr_tx
, res
->sr_pg
) == -1)
1516 if (scf_transaction_property_new(res
->sr_tx
, res
->sr_ent
,
1517 pname
, ptype
) == -1) {
1521 if (scf_transaction_property_change(res
->sr_tx
, res
->sr_ent
,
1522 pname
, ptype
) == -1) {
1527 if (scf_entry_add_value(res
->sr_ent
, res
->sr_val
) != 0)
1530 result
= scf_transaction_commit(res
->sr_tx
);
1532 scf_transaction_reset(res
->sr_tx
);
1533 if (scf_pg_update(res
->sr_pg
) == -1) {
1543 ipmgmt_log(LOG_WARNING
, "failed to save the data in SCF: %s",
1544 scf_strerror(scf_error()));
1549 * Given a `pgname'/`pname', it retrieves the value based on `ptype' and
1550 * places it in `pval'.
1553 ipmgmt_get_scfprop(scf_resources_t
*res
, const char *pgname
, const char *pname
,
1554 void *pval
, scf_type_t ptype
)
1557 scf_simple_prop_t
*prop
;
1559 prop
= scf_simple_prop_get(res
->sr_handle
, IPMGMTD_FMRI
, pgname
, pname
);
1560 numvals
= scf_simple_prop_numvalues(prop
);
1564 case SCF_TYPE_INTEGER
:
1565 *(int64_t **)pval
= scf_simple_prop_next_integer(prop
);
1567 case SCF_TYPE_ASTRING
:
1568 *(char **)pval
= scf_simple_prop_next_astring(prop
);
1572 scf_simple_prop_free(prop
);
1577 * It stores the `pval' for given `pgname'/`pname' property group in SCF.
1580 ipmgmt_set_scfprop(scf_resources_t
*res
, const char *pgname
, const char *pname
,
1581 void *pval
, scf_type_t ptype
)
1585 if ((res
->sr_pg
= scf_pg_create(res
->sr_handle
)) == NULL
) {
1586 ipmgmt_log(LOG_WARNING
, "failed to create property group: %s",
1587 scf_strerror(scf_error()));
1591 if (scf_instance_add_pg(res
->sr_inst
, pgname
, SCF_GROUP_APPLICATION
,
1592 0, res
->sr_pg
) != 0) {
1593 if ((err
= scf_error()) != SCF_ERROR_EXISTS
) {
1594 ipmgmt_log(LOG_WARNING
,
1595 "Error adding property group '%s/%s': %s",
1596 pgname
, pname
, scf_strerror(err
));
1600 * if the property group already exists, then we get the
1601 * composed view of the property group for the given instance.
1603 if (scf_instance_get_pg_composed(res
->sr_inst
, NULL
, pgname
,
1605 ipmgmt_log(LOG_WARNING
, "Error getting composed view "
1606 "of the property group '%s/%s': %s", pgname
, pname
,
1607 scf_strerror(scf_error()));
1612 return (ipmgmt_set_scfprop_value(res
, pname
, pval
, ptype
));
1616 * Returns B_TRUE, if the non-global zone is being booted for the first time
1617 * after being installed. This is required to setup the ipadm data-store for
1618 * the first boot of the non-global zone. Please see, PSARC 2010/166,
1621 * Note that, this API cannot be used to determine first boot post image-update.
1622 * 'pkg image-update' clones the current BE and the existing value of
1623 * ipmgmtd/first_boot_done will be carried forward and obviously it will be set
1627 ipmgmt_ngz_firstboot_postinstall()
1629 scf_resources_t res
;
1630 boolean_t bval
= B_TRUE
;
1633 /* we always err on the side of caution */
1634 if (ipmgmt_create_scf_resources(IPMGMTD_FMRI
, &res
) != 0)
1637 if (ipmgmt_get_scfprop(&res
, IPMGMTD_APP_PG
, IPMGMTD_PROP_FBD
, &strval
,
1638 SCF_TYPE_ASTRING
) > 0) {
1639 bval
= (strcmp(strval
, IPMGMTD_TRUESTR
) == 0 ?
1643 * IPMGMTD_PROP_FBD does not exist in the SCF. Lets create it.
1644 * Since we err on the side of caution, we ignore the return
1645 * error and return B_TRUE.
1647 (void) ipmgmt_set_scfprop(&res
, IPMGMTD_APP_PG
,
1648 IPMGMTD_PROP_FBD
, IPMGMTD_TRUESTR
, SCF_TYPE_ASTRING
);
1650 ipmgmt_release_scf_resources(&res
);
1655 * Returns B_TRUE, if the data-store needs upgrade otherwise returns B_FALSE.
1656 * Today we have to take care of, one case of, upgrading from version 0 to
1657 * version 1, so we will use boolean_t as means to decide if upgrade is needed
1658 * or not. Further, the upcoming projects might completely move the flatfile
1659 * data-store into SCF and hence we shall keep this interface simple.
1662 ipmgmt_needs_upgrade(scf_resources_t
*res
)
1664 boolean_t bval
= B_TRUE
;
1667 if (ipmgmt_get_scfprop(res
, IPMGMTD_APP_PG
, IPMGMTD_PROP_DBVER
,
1668 &verp
, SCF_TYPE_INTEGER
) > 0) {
1669 if (*verp
== IPADM_DB_VERSION
)
1673 * 'datastore_version' doesn't exist. Which means that we need to
1674 * upgrade the datastore. We will create 'datastore_version' and set
1675 * the version value to IPADM_DB_VERSION, after we upgrade the file.
1681 * This is called after the successful upgrade of the local data-store. With
1682 * the data-store upgraded to recent version we don't have to do anything on
1683 * subsequent reboots.
1686 ipmgmt_update_dbver(scf_resources_t
*res
)
1688 int64_t version
= IPADM_DB_VERSION
;
1690 (void) ipmgmt_set_scfprop(res
, IPMGMTD_APP_PG
,
1691 IPMGMTD_PROP_DBVER
, &version
, SCF_TYPE_INTEGER
);