16e91bba0SGirish Moodalbail /*
26e91bba0SGirish Moodalbail * CDDL HEADER START
36e91bba0SGirish Moodalbail *
46e91bba0SGirish Moodalbail * The contents of this file are subject to the terms of the
56e91bba0SGirish Moodalbail * Common Development and Distribution License (the "License").
66e91bba0SGirish Moodalbail * You may not use this file except in compliance with the License.
76e91bba0SGirish Moodalbail *
86e91bba0SGirish Moodalbail * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96e91bba0SGirish Moodalbail * or http://www.opensolaris.org/os/licensing.
106e91bba0SGirish Moodalbail * See the License for the specific language governing permissions
116e91bba0SGirish Moodalbail * and limitations under the License.
126e91bba0SGirish Moodalbail *
136e91bba0SGirish Moodalbail * When distributing Covered Code, include this CDDL HEADER in each
146e91bba0SGirish Moodalbail * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156e91bba0SGirish Moodalbail * If applicable, add the following below this CDDL HEADER, with the
166e91bba0SGirish Moodalbail * fields enclosed by brackets "[]" replaced with your own identifying
176e91bba0SGirish Moodalbail * information: Portions Copyright [yyyy] [name of copyright owner]
186e91bba0SGirish Moodalbail *
196e91bba0SGirish Moodalbail * CDDL HEADER END
206e91bba0SGirish Moodalbail */
216e91bba0SGirish Moodalbail
226e91bba0SGirish Moodalbail /*
23ec3706caSVasumathi Sundaram * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24ab618543SJohn Levon * Copyright 2018 Joyent, Inc.
25c985e172SIgor Kozhukhov * Copyright 2016 Argo Technologie SA.
26b31320a7SChris Fraire * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
27a73be61aSHans Rosenfeld * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
286e91bba0SGirish Moodalbail */
296e91bba0SGirish Moodalbail
306e91bba0SGirish Moodalbail /*
316e91bba0SGirish Moodalbail * Contains DB walker functions, which are of type `db_wfunc_t';
326e91bba0SGirish Moodalbail *
336e91bba0SGirish Moodalbail * typedef boolean_t db_wfunc_t(void *cbarg, nvlist_t *db_nvl, char *buf,
346e91bba0SGirish Moodalbail * size_t bufsize, int *errp);
356e91bba0SGirish Moodalbail *
366e91bba0SGirish Moodalbail * ipadm_rw_db() walks through the data store, one line at a time and calls
376e91bba0SGirish Moodalbail * these call back functions with:
386e91bba0SGirish Moodalbail * `cbarg' - callback argument
396e91bba0SGirish Moodalbail * `db_nvl' - representing a line from DB in nvlist_t form
406e91bba0SGirish Moodalbail * `buf' - character buffer to hold modified line
416e91bba0SGirish Moodalbail * `bufsize'- size of the buffer
426e91bba0SGirish Moodalbail * `errp' - captures any error inside the walker function.
436e91bba0SGirish Moodalbail *
446e91bba0SGirish Moodalbail * All the 'write' callback functions modify `db_nvl' based on `cbarg' and
456e91bba0SGirish Moodalbail * copy string representation of `db_nvl' (using ipadm_nvlist2str()) into `buf'.
466e91bba0SGirish Moodalbail * To delete a line from the DB, buf[0] is set to `\0'. Inside ipadm_rw_db(),
476e91bba0SGirish Moodalbail * the modified `buf' is written back into DB.
486e91bba0SGirish Moodalbail *
496e91bba0SGirish Moodalbail * All the 'read' callback functions, retrieve the information from the DB, by
506e91bba0SGirish Moodalbail * reading `db_nvl' and then populate the `cbarg'.
516e91bba0SGirish Moodalbail */
526e91bba0SGirish Moodalbail
536e91bba0SGirish Moodalbail #include <stdlib.h>
546e91bba0SGirish Moodalbail #include <strings.h>
556e91bba0SGirish Moodalbail #include <errno.h>
566e91bba0SGirish Moodalbail #include <assert.h>
576e91bba0SGirish Moodalbail #include <sys/types.h>
586e91bba0SGirish Moodalbail #include <sys/socket.h>
596e91bba0SGirish Moodalbail #include <netinet/in.h>
606e91bba0SGirish Moodalbail #include <arpa/inet.h>
616e91bba0SGirish Moodalbail #include <unistd.h>
626e91bba0SGirish Moodalbail #include "ipmgmt_impl.h"
638887b57dSGirish Moodalbail
648887b57dSGirish Moodalbail /* SCF related property group names and property names */
658887b57dSGirish Moodalbail #define IPMGMTD_APP_PG "ipmgmtd"
668887b57dSGirish Moodalbail #define IPMGMTD_PROP_FBD "first_boot_done"
678887b57dSGirish Moodalbail #define IPMGMTD_PROP_DBVER "datastore_version"
688887b57dSGirish Moodalbail #define IPMGMTD_TRUESTR "true"
696e91bba0SGirish Moodalbail
706e91bba0SGirish Moodalbail #define ATYPE "_atype" /* name of the address type nvpair */
716e91bba0SGirish Moodalbail #define FLAGS "_flags" /* name of the flags nvpair */
726e91bba0SGirish Moodalbail
736e91bba0SGirish Moodalbail /*
746e91bba0SGirish Moodalbail * flag used by ipmgmt_persist_aobjmap() to indicate address type is
756e91bba0SGirish Moodalbail * IPADM_ADDR_IPV6_ADDRCONF.
766e91bba0SGirish Moodalbail */
776e91bba0SGirish Moodalbail #define IPMGMT_ATYPE_V6ACONF 0x1
786e91bba0SGirish Moodalbail
796e91bba0SGirish Moodalbail extern pthread_rwlock_t ipmgmt_dbconf_lock;
806e91bba0SGirish Moodalbail
819b5bf10aSMark Haywood /* signifies whether volatile copy of data store is in use */
829b5bf10aSMark Haywood static boolean_t ipmgmt_rdonly_root = B_FALSE;
839b5bf10aSMark Haywood
84a73be61aSHans Rosenfeld typedef int ipmgmt_if_updater_func_t(nvlist_t *, nvpair_t *, uint_t);
85a73be61aSHans Rosenfeld
86a73be61aSHans Rosenfeld static ipmgmt_if_updater_func_t ipmgmt_if_family_updater;
87a73be61aSHans Rosenfeld static ipmgmt_if_updater_func_t ipmgmt_if_groupmembers_updater;
88a73be61aSHans Rosenfeld
89a73be61aSHans Rosenfeld static int ipmgmt_get_ifinfo_nvl(const char *ifname, nvlist_t **if_info_nvl);
90a73be61aSHans Rosenfeld
91a73be61aSHans Rosenfeld typedef struct {
92a73be61aSHans Rosenfeld const char *name;
93a73be61aSHans Rosenfeld ipmgmt_if_updater_func_t *func;
94a73be61aSHans Rosenfeld } ipmgmt_if_updater_ent_t;
95a73be61aSHans Rosenfeld
96a73be61aSHans Rosenfeld static ipmgmt_if_updater_ent_t ipmgmt_if_updater_ent[] = {
97a73be61aSHans Rosenfeld {IPADM_NVP_FAMILIES, ipmgmt_if_family_updater},
98a73be61aSHans Rosenfeld {IPADM_NVP_MIFNAMES, ipmgmt_if_groupmembers_updater},
99a73be61aSHans Rosenfeld {NULL, NULL}
100a73be61aSHans Rosenfeld };
101a73be61aSHans Rosenfeld
102a73be61aSHans Rosenfeld static ipmgmt_if_updater_ent_t *
ipmgmt_find_if_field_updater(const char * field_name)103a73be61aSHans Rosenfeld ipmgmt_find_if_field_updater(const char *field_name)
104a73be61aSHans Rosenfeld {
105a73be61aSHans Rosenfeld int i;
106a73be61aSHans Rosenfeld
107a73be61aSHans Rosenfeld for (i = 0; ipmgmt_if_updater_ent[i].name != NULL; i++) {
108a73be61aSHans Rosenfeld if (strcmp(field_name, ipmgmt_if_updater_ent[i].name) == 0) {
109a73be61aSHans Rosenfeld break;
110a73be61aSHans Rosenfeld }
111a73be61aSHans Rosenfeld }
112a73be61aSHans Rosenfeld
113a73be61aSHans Rosenfeld return (&ipmgmt_if_updater_ent[i]);
114a73be61aSHans Rosenfeld }
115a73be61aSHans Rosenfeld
116a73be61aSHans Rosenfeld static int
ipmgmt_if_groupmembers_updater(nvlist_t * db_nvl,nvpair_t * member_nvp,uint_t flags)117a73be61aSHans Rosenfeld ipmgmt_if_groupmembers_updater(nvlist_t *db_nvl, nvpair_t *member_nvp,
118a73be61aSHans Rosenfeld uint_t flags)
119a73be61aSHans Rosenfeld {
120a73be61aSHans Rosenfeld char **members;
121a73be61aSHans Rosenfeld char *member;
122a73be61aSHans Rosenfeld char **out_members;
123a73be61aSHans Rosenfeld uint_t nelem = 0, cnt = 0;
124a73be61aSHans Rosenfeld int err;
125a73be61aSHans Rosenfeld
126a73be61aSHans Rosenfeld if ((err = nvpair_value_string(member_nvp, &member)) != 0)
127a73be61aSHans Rosenfeld return (err);
128a73be61aSHans Rosenfeld
129a73be61aSHans Rosenfeld err = nvlist_lookup_string_array(db_nvl, IPADM_NVP_MIFNAMES,
130a73be61aSHans Rosenfeld &members, &nelem);
131a73be61aSHans Rosenfeld
132a73be61aSHans Rosenfeld if (err != 0 && (flags & IPMGMT_REMOVE))
133a73be61aSHans Rosenfeld return (ENOENT);
134a73be61aSHans Rosenfeld
135a73be61aSHans Rosenfeld /*
136a73be61aSHans Rosenfeld * Reserve one extra slot for IPMGMT_APPEND.
137a73be61aSHans Rosenfeld * Probably not worth conditionalizing.
138a73be61aSHans Rosenfeld */
139a73be61aSHans Rosenfeld out_members = calloc(nelem + 1, sizeof (char *));
140a73be61aSHans Rosenfeld if (out_members == NULL)
141a73be61aSHans Rosenfeld return (ENOMEM);
142a73be61aSHans Rosenfeld
143a73be61aSHans Rosenfeld while (nelem-- > 0) {
144a73be61aSHans Rosenfeld if ((flags & IPMGMT_REMOVE) &&
145a73be61aSHans Rosenfeld (strcmp(member, members[nelem]) == 0))
146a73be61aSHans Rosenfeld continue;
147a73be61aSHans Rosenfeld
148a73be61aSHans Rosenfeld if ((out_members[cnt] = strdup(members[nelem])) == NULL) {
149a73be61aSHans Rosenfeld err = ENOMEM;
150a73be61aSHans Rosenfeld goto fail;
151a73be61aSHans Rosenfeld }
152a73be61aSHans Rosenfeld
153a73be61aSHans Rosenfeld cnt++;
154a73be61aSHans Rosenfeld }
155a73be61aSHans Rosenfeld
156a73be61aSHans Rosenfeld if (flags & IPMGMT_APPEND) {
157a73be61aSHans Rosenfeld if ((out_members[cnt] = strdup(member)) == NULL) {
158a73be61aSHans Rosenfeld err = ENOMEM;
159a73be61aSHans Rosenfeld goto fail;
160a73be61aSHans Rosenfeld }
161a73be61aSHans Rosenfeld cnt++;
162a73be61aSHans Rosenfeld }
163a73be61aSHans Rosenfeld
164a73be61aSHans Rosenfeld if (cnt == 0) {
165a73be61aSHans Rosenfeld err = nvlist_remove(db_nvl, IPADM_NVP_MIFNAMES,
166a73be61aSHans Rosenfeld DATA_TYPE_STRING_ARRAY);
167a73be61aSHans Rosenfeld } else {
168a73be61aSHans Rosenfeld err = nvlist_add_string_array(db_nvl, IPADM_NVP_MIFNAMES,
169a73be61aSHans Rosenfeld out_members, cnt);
170a73be61aSHans Rosenfeld }
171a73be61aSHans Rosenfeld
172a73be61aSHans Rosenfeld fail:
173a73be61aSHans Rosenfeld while (cnt--)
174a73be61aSHans Rosenfeld free(out_members[cnt]);
175a73be61aSHans Rosenfeld
176a73be61aSHans Rosenfeld free(out_members);
177a73be61aSHans Rosenfeld
178a73be61aSHans Rosenfeld return (err);
179a73be61aSHans Rosenfeld }
180a73be61aSHans Rosenfeld
181a73be61aSHans Rosenfeld static int
ipmgmt_if_family_updater(nvlist_t * db_nvl,nvpair_t * families_nvp,uint_t flags)182a73be61aSHans Rosenfeld ipmgmt_if_family_updater(nvlist_t *db_nvl, nvpair_t *families_nvp, uint_t flags)
183a73be61aSHans Rosenfeld {
184a73be61aSHans Rosenfeld uint16_t *families;
185a73be61aSHans Rosenfeld uint_t nelem = 0;
186a73be61aSHans Rosenfeld int err;
187a73be61aSHans Rosenfeld
188a73be61aSHans Rosenfeld if ((err = nvpair_value_uint16_array(families_nvp, &families,
189a73be61aSHans Rosenfeld &nelem)) != 0)
190a73be61aSHans Rosenfeld return (err);
191a73be61aSHans Rosenfeld
192a73be61aSHans Rosenfeld return (ipmgmt_update_family_nvp(db_nvl, families[0], flags));
193a73be61aSHans Rosenfeld }
194a73be61aSHans Rosenfeld
195a73be61aSHans Rosenfeld int
ipmgmt_update_family_nvp(nvlist_t * nvl,sa_family_t af,uint_t flags)196a73be61aSHans Rosenfeld ipmgmt_update_family_nvp(nvlist_t *nvl, sa_family_t af, uint_t flags)
197a73be61aSHans Rosenfeld {
198a73be61aSHans Rosenfeld uint16_t *families = NULL;
199a73be61aSHans Rosenfeld uint16_t out_families[2];
200a73be61aSHans Rosenfeld uint_t nelem = 0, cnt;
201a73be61aSHans Rosenfeld int err;
202a73be61aSHans Rosenfeld
203a73be61aSHans Rosenfeld err = nvlist_lookup_uint16_array(nvl, IPADM_NVP_FAMILIES,
204a73be61aSHans Rosenfeld &families, &nelem);
205a73be61aSHans Rosenfeld if (err != 0 && (flags & IPMGMT_REMOVE)) {
206a73be61aSHans Rosenfeld return (ENOENT);
207a73be61aSHans Rosenfeld }
208a73be61aSHans Rosenfeld
209a73be61aSHans Rosenfeld if (flags & IPMGMT_APPEND) {
210a73be61aSHans Rosenfeld if (families != NULL) {
211a73be61aSHans Rosenfeld if (nelem == 2 || families[0] == af) {
212a73be61aSHans Rosenfeld return (EEXIST);
213a73be61aSHans Rosenfeld }
214a73be61aSHans Rosenfeld out_families[0] = families[0];
215a73be61aSHans Rosenfeld out_families[1] = af;
216a73be61aSHans Rosenfeld cnt = 2;
217a73be61aSHans Rosenfeld } else {
218a73be61aSHans Rosenfeld out_families[0] = af;
219a73be61aSHans Rosenfeld cnt = 1;
220a73be61aSHans Rosenfeld }
221a73be61aSHans Rosenfeld } else {
222a73be61aSHans Rosenfeld assert(nelem == 1 || nelem == 2);
223a73be61aSHans Rosenfeld cnt = 0;
224a73be61aSHans Rosenfeld while (nelem-- > 0) {
225a73be61aSHans Rosenfeld if (families[nelem] != af) {
226a73be61aSHans Rosenfeld out_families[cnt] = families[nelem];
227a73be61aSHans Rosenfeld cnt++;
228a73be61aSHans Rosenfeld }
229a73be61aSHans Rosenfeld }
230a73be61aSHans Rosenfeld }
231a73be61aSHans Rosenfeld
232a73be61aSHans Rosenfeld if (cnt != 0) {
233a73be61aSHans Rosenfeld return (nvlist_add_uint16_array(nvl, IPADM_NVP_FAMILIES,
234a73be61aSHans Rosenfeld out_families, cnt));
235a73be61aSHans Rosenfeld }
236a73be61aSHans Rosenfeld return (nvlist_remove(nvl, IPADM_NVP_FAMILIES, DATA_TYPE_UINT16_ARRAY));
237a73be61aSHans Rosenfeld }
238a73be61aSHans Rosenfeld
2396e91bba0SGirish Moodalbail /*
2406e91bba0SGirish Moodalbail * Checks if the database nvl, `db_nvl' contains and matches ALL of the passed
2416e91bba0SGirish Moodalbail * in private nvpairs `proto', `ifname' & `aobjname'.
2426e91bba0SGirish Moodalbail */
2436e91bba0SGirish Moodalbail static boolean_t
ipmgmt_nvlist_match(nvlist_t * db_nvl,const char * proto,const char * ifname,const char * aobjname)2446e91bba0SGirish Moodalbail ipmgmt_nvlist_match(nvlist_t *db_nvl, const char *proto, const char *ifname,
2456e91bba0SGirish Moodalbail const char *aobjname)
2466e91bba0SGirish Moodalbail {
2476e91bba0SGirish Moodalbail char *db_proto = NULL, *db_ifname = NULL;
2486e91bba0SGirish Moodalbail char *db_aobjname = NULL;
2496e91bba0SGirish Moodalbail nvpair_t *nvp;
2506e91bba0SGirish Moodalbail char *name;
2516e91bba0SGirish Moodalbail
2526e91bba0SGirish Moodalbail /* walk through db_nvl and retrieve all its private nvpairs */
2536e91bba0SGirish Moodalbail for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
2546e91bba0SGirish Moodalbail nvp = nvlist_next_nvpair(db_nvl, nvp)) {
2556e91bba0SGirish Moodalbail name = nvpair_name(nvp);
2566e91bba0SGirish Moodalbail if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
2576e91bba0SGirish Moodalbail (void) nvpair_value_string(nvp, &db_proto);
2586e91bba0SGirish Moodalbail else if (strcmp(IPADM_NVP_IFNAME, name) == 0)
2596e91bba0SGirish Moodalbail (void) nvpair_value_string(nvp, &db_ifname);
2606e91bba0SGirish Moodalbail else if (strcmp(IPADM_NVP_AOBJNAME, name) == 0)
2616e91bba0SGirish Moodalbail (void) nvpair_value_string(nvp, &db_aobjname);
2626e91bba0SGirish Moodalbail }
2636e91bba0SGirish Moodalbail
2646e91bba0SGirish Moodalbail if (proto != NULL && proto[0] == '\0')
2656e91bba0SGirish Moodalbail proto = NULL;
2666e91bba0SGirish Moodalbail if (ifname != NULL && ifname[0] == '\0')
2676e91bba0SGirish Moodalbail ifname = NULL;
2686e91bba0SGirish Moodalbail if (aobjname != NULL && aobjname[0] == '\0')
2696e91bba0SGirish Moodalbail aobjname = NULL;
2706e91bba0SGirish Moodalbail
2716e91bba0SGirish Moodalbail if ((proto == NULL && db_proto != NULL) ||
2726e91bba0SGirish Moodalbail (proto != NULL && db_proto == NULL) ||
273c985e172SIgor Kozhukhov (proto != NULL && db_proto != NULL &&
274c985e172SIgor Kozhukhov strcmp(proto, db_proto) != 0)) {
2756e91bba0SGirish Moodalbail /* no intersection - different protocols. */
2766e91bba0SGirish Moodalbail return (B_FALSE);
2776e91bba0SGirish Moodalbail }
2786e91bba0SGirish Moodalbail if ((ifname == NULL && db_ifname != NULL) ||
2796e91bba0SGirish Moodalbail (ifname != NULL && db_ifname == NULL) ||
280c985e172SIgor Kozhukhov (ifname != NULL && db_ifname != NULL &&
281c985e172SIgor Kozhukhov strcmp(ifname, db_ifname) != 0)) {
2826e91bba0SGirish Moodalbail /* no intersection - different interfaces. */
2836e91bba0SGirish Moodalbail return (B_FALSE);
2846e91bba0SGirish Moodalbail }
2856e91bba0SGirish Moodalbail if ((aobjname == NULL && db_aobjname != NULL) ||
2866e91bba0SGirish Moodalbail (aobjname != NULL && db_aobjname == NULL) ||
287c985e172SIgor Kozhukhov (aobjname != NULL && db_aobjname != NULL &&
288c985e172SIgor Kozhukhov strcmp(aobjname, db_aobjname) != 0)) {
2896e91bba0SGirish Moodalbail /* no intersection - different address objects */
2906e91bba0SGirish Moodalbail return (B_FALSE);
2916e91bba0SGirish Moodalbail }
2926e91bba0SGirish Moodalbail
2936e91bba0SGirish Moodalbail return (B_TRUE);
2946e91bba0SGirish Moodalbail }
2956e91bba0SGirish Moodalbail
2966e91bba0SGirish Moodalbail /*
2976e91bba0SGirish Moodalbail * Checks if the database nvl, `db_nvl' and the input nvl, `in_nvl' intersects.
2986e91bba0SGirish Moodalbail */
2996e91bba0SGirish Moodalbail static boolean_t
ipmgmt_nvlist_intersects(nvlist_t * db_nvl,nvlist_t * in_nvl)3006e91bba0SGirish Moodalbail ipmgmt_nvlist_intersects(nvlist_t *db_nvl, nvlist_t *in_nvl)
3016e91bba0SGirish Moodalbail {
3026e91bba0SGirish Moodalbail nvpair_t *nvp;
3036e91bba0SGirish Moodalbail char *name;
3046e91bba0SGirish Moodalbail char *proto = NULL, *ifname = NULL, *aobjname = NULL;
3056e91bba0SGirish Moodalbail
3066e91bba0SGirish Moodalbail /* walk through in_nvl and retrieve all its private nvpairs */
3076e91bba0SGirish Moodalbail for (nvp = nvlist_next_nvpair(in_nvl, NULL); nvp != NULL;
3086e91bba0SGirish Moodalbail nvp = nvlist_next_nvpair(in_nvl, nvp)) {
3096e91bba0SGirish Moodalbail name = nvpair_name(nvp);
3106e91bba0SGirish Moodalbail if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
3116e91bba0SGirish Moodalbail (void) nvpair_value_string(nvp, &proto);
3126e91bba0SGirish Moodalbail else if (strcmp(IPADM_NVP_IFNAME, name) == 0)
3136e91bba0SGirish Moodalbail (void) nvpair_value_string(nvp, &ifname);
3146e91bba0SGirish Moodalbail else if (strcmp(IPADM_NVP_AOBJNAME, name) == 0)
3156e91bba0SGirish Moodalbail (void) nvpair_value_string(nvp, &aobjname);
3166e91bba0SGirish Moodalbail }
3176e91bba0SGirish Moodalbail
3186e91bba0SGirish Moodalbail return (ipmgmt_nvlist_match(db_nvl, proto, ifname, aobjname));
3196e91bba0SGirish Moodalbail }
3206e91bba0SGirish Moodalbail
3216e91bba0SGirish Moodalbail /*
3226e91bba0SGirish Moodalbail * Checks if the database nvl, `db_nvl', contains and matches ANY of the passed
3236e91bba0SGirish Moodalbail * in private nvpairs `proto', `ifname' & `aobjname'.
3246e91bba0SGirish Moodalbail */
3256e91bba0SGirish Moodalbail static boolean_t
ipmgmt_nvlist_contains(nvlist_t * db_nvl,const char * proto,const char * ifname,char * aobjname)3266e91bba0SGirish Moodalbail ipmgmt_nvlist_contains(nvlist_t *db_nvl, const char *proto,
3276e91bba0SGirish Moodalbail const char *ifname, char *aobjname)
3286e91bba0SGirish Moodalbail {
3296e91bba0SGirish Moodalbail char *db_ifname = NULL, *db_proto = NULL;
3306e91bba0SGirish Moodalbail char *db_aobjname = NULL;
3316e91bba0SGirish Moodalbail nvpair_t *nvp;
3326e91bba0SGirish Moodalbail char *name;
3336e91bba0SGirish Moodalbail
3346e91bba0SGirish Moodalbail /* walk through db_nvl and retrieve all private nvpairs */
3356e91bba0SGirish Moodalbail for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
3366e91bba0SGirish Moodalbail nvp = nvlist_next_nvpair(db_nvl, nvp)) {
3376e91bba0SGirish Moodalbail name = nvpair_name(nvp);
3386e91bba0SGirish Moodalbail if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
3396e91bba0SGirish Moodalbail (void) nvpair_value_string(nvp, &db_proto);
3406e91bba0SGirish Moodalbail else if (strcmp(IPADM_NVP_IFNAME, name) == 0)
3416e91bba0SGirish Moodalbail (void) nvpair_value_string(nvp, &db_ifname);
3426e91bba0SGirish Moodalbail else if (strcmp(IPADM_NVP_AOBJNAME, name) == 0)
3436e91bba0SGirish Moodalbail (void) nvpair_value_string(nvp, &db_aobjname);
3446e91bba0SGirish Moodalbail }
3456e91bba0SGirish Moodalbail
3466e91bba0SGirish Moodalbail if (proto != NULL && proto[0] != '\0') {
3476e91bba0SGirish Moodalbail if ((db_proto == NULL || strcmp(proto, db_proto) != 0))
3486e91bba0SGirish Moodalbail return (B_FALSE);
3496e91bba0SGirish Moodalbail }
3506e91bba0SGirish Moodalbail if (ifname != NULL && ifname[0] != '\0') {
3516e91bba0SGirish Moodalbail if ((db_ifname == NULL || strcmp(ifname, db_ifname) != 0))
3526e91bba0SGirish Moodalbail return (B_FALSE);
3536e91bba0SGirish Moodalbail }
3546e91bba0SGirish Moodalbail if (aobjname != NULL && aobjname[0] != '\0') {
3556e91bba0SGirish Moodalbail if ((db_aobjname == NULL || strcmp(aobjname, db_aobjname) != 0))
3566e91bba0SGirish Moodalbail return (B_FALSE);
3576e91bba0SGirish Moodalbail }
3586e91bba0SGirish Moodalbail
3596e91bba0SGirish Moodalbail return (B_TRUE);
3606e91bba0SGirish Moodalbail }
3616e91bba0SGirish Moodalbail
3626e91bba0SGirish Moodalbail /*
3636e91bba0SGirish Moodalbail * Retrieves the property value from the DB. The property whose value is to be
3646e91bba0SGirish Moodalbail * retrieved is in `pargp->ia_pname'.
3656e91bba0SGirish Moodalbail */
3666e91bba0SGirish Moodalbail /* ARGSUSED */
3676e91bba0SGirish Moodalbail boolean_t
ipmgmt_db_getprop(void * arg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)3686e91bba0SGirish Moodalbail ipmgmt_db_getprop(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
3696e91bba0SGirish Moodalbail int *errp)
3706e91bba0SGirish Moodalbail {
3716e91bba0SGirish Moodalbail ipmgmt_prop_arg_t *pargp = arg;
3726e91bba0SGirish Moodalbail boolean_t cont = B_TRUE;
3736e91bba0SGirish Moodalbail char *pval;
3746e91bba0SGirish Moodalbail int err = 0;
3756e91bba0SGirish Moodalbail
3766e91bba0SGirish Moodalbail *errp = 0;
3776e91bba0SGirish Moodalbail
3786e91bba0SGirish Moodalbail if (!ipmgmt_nvlist_match(db_nvl, pargp->ia_module,
3796e91bba0SGirish Moodalbail pargp->ia_ifname, pargp->ia_aobjname))
3806e91bba0SGirish Moodalbail return (B_TRUE);
3816e91bba0SGirish Moodalbail
3826e91bba0SGirish Moodalbail if ((err = nvlist_lookup_string(db_nvl, pargp->ia_pname,
3836e91bba0SGirish Moodalbail &pval)) == 0) {
3846e91bba0SGirish Moodalbail (void) strlcpy(pargp->ia_pval, pval, sizeof (pargp->ia_pval));
3856e91bba0SGirish Moodalbail /*
3866e91bba0SGirish Moodalbail * We have retrieved what we are looking for.
3876e91bba0SGirish Moodalbail * Stop the walker.
3886e91bba0SGirish Moodalbail */
3896e91bba0SGirish Moodalbail cont = B_FALSE;
3906e91bba0SGirish Moodalbail } else {
3916e91bba0SGirish Moodalbail if (err == ENOENT)
3926e91bba0SGirish Moodalbail err = 0;
3936e91bba0SGirish Moodalbail *errp = err;
3946e91bba0SGirish Moodalbail }
3956e91bba0SGirish Moodalbail
3966e91bba0SGirish Moodalbail return (cont);
3976e91bba0SGirish Moodalbail }
3986e91bba0SGirish Moodalbail
3996e91bba0SGirish Moodalbail /*
4006e91bba0SGirish Moodalbail * Removes the property value from the DB. The property whose value is to be
4016e91bba0SGirish Moodalbail * removed is in `pargp->ia_pname'.
4026e91bba0SGirish Moodalbail */
4036e91bba0SGirish Moodalbail /* ARGSUSED */
4046e91bba0SGirish Moodalbail boolean_t
ipmgmt_db_resetprop(void * arg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)4056e91bba0SGirish Moodalbail ipmgmt_db_resetprop(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
4066e91bba0SGirish Moodalbail int *errp)
4076e91bba0SGirish Moodalbail {
4086e91bba0SGirish Moodalbail ipmgmt_prop_arg_t *pargp = arg;
4096e91bba0SGirish Moodalbail
4106e91bba0SGirish Moodalbail *errp = 0;
4116e91bba0SGirish Moodalbail if (!ipmgmt_nvlist_match(db_nvl, pargp->ia_module,
4126e91bba0SGirish Moodalbail pargp->ia_ifname, pargp->ia_aobjname))
4136e91bba0SGirish Moodalbail return (B_TRUE);
4146e91bba0SGirish Moodalbail
4156e91bba0SGirish Moodalbail if (!nvlist_exists(db_nvl, pargp->ia_pname))
4166e91bba0SGirish Moodalbail return (B_TRUE);
4176e91bba0SGirish Moodalbail
4186e91bba0SGirish Moodalbail /*
4196e91bba0SGirish Moodalbail * We found the property in the DB. If IPMGMT_REMOVE is not set then
4206e91bba0SGirish Moodalbail * delete the entry from the db. If it is set, then the property is a
4216e91bba0SGirish Moodalbail * multi-valued property so just remove the specified values from DB.
4226e91bba0SGirish Moodalbail */
4236e91bba0SGirish Moodalbail if (pargp->ia_flags & IPMGMT_REMOVE) {
4246e91bba0SGirish Moodalbail char *dbpval = NULL;
4256e91bba0SGirish Moodalbail char *inpval = pargp->ia_pval;
4266e91bba0SGirish Moodalbail char pval[MAXPROPVALLEN];
4276e91bba0SGirish Moodalbail char *val, *lasts;
4286e91bba0SGirish Moodalbail
4296e91bba0SGirish Moodalbail *errp = nvlist_lookup_string(db_nvl, pargp->ia_pname, &dbpval);
4306e91bba0SGirish Moodalbail if (*errp != 0)
4316e91bba0SGirish Moodalbail return (B_FALSE);
4326e91bba0SGirish Moodalbail
4336e91bba0SGirish Moodalbail /*
4346e91bba0SGirish Moodalbail * multi-valued properties are represented as comma separated
4356e91bba0SGirish Moodalbail * values. Use string tokenizer functions to split them and
4366e91bba0SGirish Moodalbail * search for the value to be removed.
4376e91bba0SGirish Moodalbail */
4386e91bba0SGirish Moodalbail bzero(pval, sizeof (pval));
4396e91bba0SGirish Moodalbail if ((val = strtok_r(dbpval, ",", &lasts)) != NULL) {
4406e91bba0SGirish Moodalbail if (strcmp(val, inpval) != 0)
4416e91bba0SGirish Moodalbail (void) strlcat(pval, val, MAXPROPVALLEN);
4426e91bba0SGirish Moodalbail while ((val = strtok_r(NULL, ",", &lasts)) != NULL) {
4436e91bba0SGirish Moodalbail if (strcmp(val, inpval) != 0) {
4446e91bba0SGirish Moodalbail if (pval[0] != '\0')
4456e91bba0SGirish Moodalbail (void) strlcat(pval, ",",
4466e91bba0SGirish Moodalbail MAXPROPVALLEN);
4476e91bba0SGirish Moodalbail (void) strlcat(pval, val,
4486e91bba0SGirish Moodalbail MAXPROPVALLEN);
4496e91bba0SGirish Moodalbail }
4506e91bba0SGirish Moodalbail }
4516e91bba0SGirish Moodalbail } else {
4526e91bba0SGirish Moodalbail if (strcmp(dbpval, inpval) != 0)
4536e91bba0SGirish Moodalbail *errp = ENOENT;
4546e91bba0SGirish Moodalbail else
4556e91bba0SGirish Moodalbail buf[0] = '\0';
4566e91bba0SGirish Moodalbail return (B_FALSE);
4576e91bba0SGirish Moodalbail }
4586e91bba0SGirish Moodalbail *errp = nvlist_add_string(db_nvl, pargp->ia_pname, pval);
4596e91bba0SGirish Moodalbail if (*errp != 0)
4606e91bba0SGirish Moodalbail return (B_FALSE);
4616e91bba0SGirish Moodalbail
4626e91bba0SGirish Moodalbail (void) memset(buf, 0, buflen);
4636e91bba0SGirish Moodalbail if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
4646e91bba0SGirish Moodalbail /* buffer overflow */
4656e91bba0SGirish Moodalbail *errp = ENOBUFS;
4666e91bba0SGirish Moodalbail }
4676e91bba0SGirish Moodalbail } else {
4686e91bba0SGirish Moodalbail buf[0] = '\0';
4696e91bba0SGirish Moodalbail }
4706e91bba0SGirish Moodalbail
4716e91bba0SGirish Moodalbail /* stop the search */
4726e91bba0SGirish Moodalbail return (B_FALSE);
4736e91bba0SGirish Moodalbail }
4746e91bba0SGirish Moodalbail
4756e91bba0SGirish Moodalbail /*
4766e91bba0SGirish Moodalbail * Input arguments can have IPADM_NVP_AOBJNAME or IPADM_NVP_IFNAME. A match is
4776e91bba0SGirish Moodalbail * found, when one of the following occurs first.
4786e91bba0SGirish Moodalbail * - the input aobjname matches the db aobjname. Return the db address.
4796e91bba0SGirish Moodalbail * - the input interface matches the db interface. Return all the
4806e91bba0SGirish Moodalbail * matching db lines with addresses.
4816e91bba0SGirish Moodalbail */
4826e91bba0SGirish Moodalbail /* ARGSUSED */
4836e91bba0SGirish Moodalbail boolean_t
ipmgmt_db_getaddr(void * arg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)4846e91bba0SGirish Moodalbail ipmgmt_db_getaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
4856e91bba0SGirish Moodalbail int *errp)
4866e91bba0SGirish Moodalbail {
487a73be61aSHans Rosenfeld ipmgmt_get_cbarg_t *cbarg = arg;
4886e91bba0SGirish Moodalbail char *db_aobjname = NULL;
4896e91bba0SGirish Moodalbail char *db_ifname = NULL;
4906e91bba0SGirish Moodalbail nvlist_t *db_addr = NULL;
4916e91bba0SGirish Moodalbail char name[IPMGMT_STRSIZE];
4926e91bba0SGirish Moodalbail nvpair_t *nvp;
4936e91bba0SGirish Moodalbail boolean_t add_nvl = B_FALSE;
4946e91bba0SGirish Moodalbail
4956e91bba0SGirish Moodalbail /* Parse db nvlist */
4966e91bba0SGirish Moodalbail for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
4976e91bba0SGirish Moodalbail nvp = nvlist_next_nvpair(db_nvl, nvp)) {
4986e91bba0SGirish Moodalbail if (nvpair_type(nvp) == DATA_TYPE_NVLIST)
4996e91bba0SGirish Moodalbail (void) nvpair_value_nvlist(nvp, &db_addr);
5006e91bba0SGirish Moodalbail else if (strcmp(nvpair_name(nvp), IPADM_NVP_IFNAME) == 0)
5016e91bba0SGirish Moodalbail (void) nvpair_value_string(nvp, &db_ifname);
5026e91bba0SGirish Moodalbail else if (strcmp(nvpair_name(nvp), IPADM_NVP_AOBJNAME) == 0)
5036e91bba0SGirish Moodalbail (void) nvpair_value_string(nvp, &db_aobjname);
5046e91bba0SGirish Moodalbail }
5056e91bba0SGirish Moodalbail
5066e91bba0SGirish Moodalbail if (db_aobjname == NULL) /* Not an address */
5076e91bba0SGirish Moodalbail return (B_TRUE);
5086e91bba0SGirish Moodalbail
5096e91bba0SGirish Moodalbail /* Check for a match between the aobjnames or the interface name */
5106e91bba0SGirish Moodalbail if (cbarg->cb_aobjname[0] != '\0') {
5116e91bba0SGirish Moodalbail if (strcmp(cbarg->cb_aobjname, db_aobjname) == 0)
5126e91bba0SGirish Moodalbail add_nvl = B_TRUE;
5136e91bba0SGirish Moodalbail } else if (cbarg->cb_ifname[0] != '\0') {
5146e91bba0SGirish Moodalbail if (strcmp(cbarg->cb_ifname, db_ifname) == 0)
5156e91bba0SGirish Moodalbail add_nvl = B_TRUE;
5166e91bba0SGirish Moodalbail } else {
5176e91bba0SGirish Moodalbail add_nvl = B_TRUE;
5186e91bba0SGirish Moodalbail }
5196e91bba0SGirish Moodalbail
5206e91bba0SGirish Moodalbail if (add_nvl) {
5216e91bba0SGirish Moodalbail (void) snprintf(name, sizeof (name), "%s_%d", db_ifname,
5226e91bba0SGirish Moodalbail cbarg->cb_ocnt);
5236e91bba0SGirish Moodalbail *errp = nvlist_add_nvlist(cbarg->cb_onvl, name, db_nvl);
5246e91bba0SGirish Moodalbail if (*errp == 0)
5256e91bba0SGirish Moodalbail cbarg->cb_ocnt++;
5266e91bba0SGirish Moodalbail }
5276e91bba0SGirish Moodalbail return (B_TRUE);
5286e91bba0SGirish Moodalbail }
5296e91bba0SGirish Moodalbail
5309b5bf10aSMark Haywood /*
5319b5bf10aSMark Haywood * This function only gets called if a volatile filesystem version
5329b5bf10aSMark Haywood * of the configuration file has been created. This only happens in the
5339b5bf10aSMark Haywood * extremely rare case that a request has been made to update the configuration
5349b5bf10aSMark Haywood * file at boottime while the root filesystem was read-only. This is
5359b5bf10aSMark Haywood * really a rare occurrence now that we don't support UFS root filesystems
5369b5bf10aSMark Haywood * any longer. This function will periodically attempt to write the
5379b5bf10aSMark Haywood * configuration back to its location on the root filesystem. Success
5389b5bf10aSMark Haywood * will indicate that the filesystem is no longer read-only.
5399b5bf10aSMark Haywood */
5409b5bf10aSMark Haywood /* ARGSUSED */
5419b5bf10aSMark Haywood static void *
ipmgmt_db_restore_thread(void * arg)5429b5bf10aSMark Haywood ipmgmt_db_restore_thread(void *arg)
5439b5bf10aSMark Haywood {
5449b5bf10aSMark Haywood int err;
5459b5bf10aSMark Haywood
5469b5bf10aSMark Haywood for (;;) {
5479b5bf10aSMark Haywood (void) sleep(5);
5489b5bf10aSMark Haywood (void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock);
5499b5bf10aSMark Haywood if (!ipmgmt_rdonly_root)
5509b5bf10aSMark Haywood break;
5519b5bf10aSMark Haywood err = ipmgmt_cpfile(IPADM_VOL_DB_FILE, IPADM_DB_FILE, B_FALSE);
5529b5bf10aSMark Haywood if (err == 0) {
5539b5bf10aSMark Haywood ipmgmt_rdonly_root = B_FALSE;
5549b5bf10aSMark Haywood break;
5559b5bf10aSMark Haywood }
5569b5bf10aSMark Haywood (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
5579b5bf10aSMark Haywood }
5589b5bf10aSMark Haywood (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
5599b5bf10aSMark Haywood return (NULL);
5609b5bf10aSMark Haywood }
5619b5bf10aSMark Haywood
5626e91bba0SGirish Moodalbail /*
5636e91bba0SGirish Moodalbail * This function takes the appropriate lock, read or write, based on the
5649b5bf10aSMark Haywood * `db_op' and then calls DB walker ipadm_rw_db(). The code is complicated
5659b5bf10aSMark Haywood * by the fact that we are not always guaranteed to have a writable root
5669b5bf10aSMark Haywood * filesystem since it is possible that we are reading or writing during
5679b5bf10aSMark Haywood * bootime while the root filesystem is still read-only. This is, by far,
5689b5bf10aSMark Haywood * the exception case. Normally, this function will be called when the
5699b5bf10aSMark Haywood * root filesystem is writable. In the unusual case where this is not
5709b5bf10aSMark Haywood * true, the configuration file is copied to the volatile file system
5719b5bf10aSMark Haywood * and is updated there until the root filesystem becomes writable. At
5729b5bf10aSMark Haywood * that time the file will be moved back to its proper location by
5739b5bf10aSMark Haywood * ipmgmt_db_restore_thread().
5746e91bba0SGirish Moodalbail */
5756e91bba0SGirish Moodalbail extern int
ipmgmt_db_walk(db_wfunc_t * db_walk_func,void * db_warg,ipadm_db_op_t db_op)5766e91bba0SGirish Moodalbail ipmgmt_db_walk(db_wfunc_t *db_walk_func, void *db_warg, ipadm_db_op_t db_op)
5776e91bba0SGirish Moodalbail {
5786e91bba0SGirish Moodalbail int err;
5796e91bba0SGirish Moodalbail boolean_t writeop;
5806e91bba0SGirish Moodalbail mode_t mode;
5819b5bf10aSMark Haywood pthread_t tid;
5828887b57dSGirish Moodalbail pthread_attr_t attr;
5836e91bba0SGirish Moodalbail
5846e91bba0SGirish Moodalbail writeop = (db_op != IPADM_DB_READ);
5856e91bba0SGirish Moodalbail if (writeop) {
5866e91bba0SGirish Moodalbail (void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock);
5876e91bba0SGirish Moodalbail mode = IPADM_FILE_MODE;
5886e91bba0SGirish Moodalbail } else {
5896e91bba0SGirish Moodalbail (void) pthread_rwlock_rdlock(&ipmgmt_dbconf_lock);
5906e91bba0SGirish Moodalbail mode = 0;
5916e91bba0SGirish Moodalbail }
5926e91bba0SGirish Moodalbail
5939b5bf10aSMark Haywood /*
5949b5bf10aSMark Haywood * Did a previous write attempt fail? If so, don't even try to
5959b5bf10aSMark Haywood * read/write to IPADM_DB_FILE.
5969b5bf10aSMark Haywood */
5979b5bf10aSMark Haywood if (!ipmgmt_rdonly_root) {
5989b5bf10aSMark Haywood err = ipadm_rw_db(db_walk_func, db_warg, IPADM_DB_FILE,
5999b5bf10aSMark Haywood mode, db_op);
6009b5bf10aSMark Haywood if (err != EROFS)
6019b5bf10aSMark Haywood goto done;
6029b5bf10aSMark Haywood }
6039b5bf10aSMark Haywood
6049b5bf10aSMark Haywood /*
6059b5bf10aSMark Haywood * If we haven't already copied the file to the volatile
6069b5bf10aSMark Haywood * file system, do so. This should only happen on a failed
6079b5bf10aSMark Haywood * writeop(i.e., we have acquired the write lock above).
6089b5bf10aSMark Haywood */
6099b5bf10aSMark Haywood if (access(IPADM_VOL_DB_FILE, F_OK) != 0) {
6109b5bf10aSMark Haywood assert(writeop);
6119b5bf10aSMark Haywood err = ipmgmt_cpfile(IPADM_DB_FILE, IPADM_VOL_DB_FILE, B_TRUE);
6129b5bf10aSMark Haywood if (err != 0)
6139b5bf10aSMark Haywood goto done;
6148887b57dSGirish Moodalbail (void) pthread_attr_init(&attr);
6158887b57dSGirish Moodalbail (void) pthread_attr_setdetachstate(&attr,
6168887b57dSGirish Moodalbail PTHREAD_CREATE_DETACHED);
617ab618543SJohn Levon (void) pthread_attr_setname_np(&attr, "db_restore");
6188887b57dSGirish Moodalbail err = pthread_create(&tid, &attr, ipmgmt_db_restore_thread,
6199b5bf10aSMark Haywood NULL);
6208887b57dSGirish Moodalbail (void) pthread_attr_destroy(&attr);
6219b5bf10aSMark Haywood if (err != 0) {
6229b5bf10aSMark Haywood (void) unlink(IPADM_VOL_DB_FILE);
6239b5bf10aSMark Haywood goto done;
6249b5bf10aSMark Haywood }
6259b5bf10aSMark Haywood ipmgmt_rdonly_root = B_TRUE;
6269b5bf10aSMark Haywood }
6279b5bf10aSMark Haywood
6289b5bf10aSMark Haywood /*
6299b5bf10aSMark Haywood * Read/write from the volatile copy.
6309b5bf10aSMark Haywood */
6319b5bf10aSMark Haywood err = ipadm_rw_db(db_walk_func, db_warg, IPADM_VOL_DB_FILE,
6329b5bf10aSMark Haywood mode, db_op);
6339b5bf10aSMark Haywood done:
6346e91bba0SGirish Moodalbail (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
6356e91bba0SGirish Moodalbail return (err);
6366e91bba0SGirish Moodalbail }
6376e91bba0SGirish Moodalbail
6386e91bba0SGirish Moodalbail /*
6396e91bba0SGirish Moodalbail * Used to add an entry towards the end of DB. It just returns B_TRUE for
6406e91bba0SGirish Moodalbail * every line of the DB. When we reach the end, ipadm_rw_db() adds the
6416e91bba0SGirish Moodalbail * line at the end.
6426e91bba0SGirish Moodalbail */
6436e91bba0SGirish Moodalbail /* ARGSUSED */
6446e91bba0SGirish Moodalbail boolean_t
ipmgmt_db_add(void * arg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)6456e91bba0SGirish Moodalbail ipmgmt_db_add(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen, int *errp)
6466e91bba0SGirish Moodalbail {
6476e91bba0SGirish Moodalbail return (B_TRUE);
6486e91bba0SGirish Moodalbail }
6496e91bba0SGirish Moodalbail
6506e91bba0SGirish Moodalbail /*
6516e91bba0SGirish Moodalbail * This function is used to update or create an entry in DB. The nvlist_t,
6526e91bba0SGirish Moodalbail * `in_nvl', represents the line we are looking for. Once we ensure the right
6536e91bba0SGirish Moodalbail * line from DB, we update that entry.
6546e91bba0SGirish Moodalbail */
6556e91bba0SGirish Moodalbail boolean_t
ipmgmt_db_update(void * arg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)6566e91bba0SGirish Moodalbail ipmgmt_db_update(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
6576e91bba0SGirish Moodalbail int *errp)
6586e91bba0SGirish Moodalbail {
6596e91bba0SGirish Moodalbail ipadm_dbwrite_cbarg_t *cb = arg;
6606e91bba0SGirish Moodalbail uint_t flags = cb->dbw_flags;
6616e91bba0SGirish Moodalbail nvlist_t *in_nvl = cb->dbw_nvl;
6626e91bba0SGirish Moodalbail nvpair_t *nvp;
6636e91bba0SGirish Moodalbail char *name, *instrval = NULL, *dbstrval = NULL;
6646e91bba0SGirish Moodalbail char pval[MAXPROPVALLEN];
6656e91bba0SGirish Moodalbail
6668887b57dSGirish Moodalbail *errp = 0;
6676e91bba0SGirish Moodalbail if (!ipmgmt_nvlist_intersects(db_nvl, in_nvl))
6686e91bba0SGirish Moodalbail return (B_TRUE);
6696e91bba0SGirish Moodalbail
6706e91bba0SGirish Moodalbail for (nvp = nvlist_next_nvpair(in_nvl, NULL); nvp != NULL;
6716e91bba0SGirish Moodalbail nvp = nvlist_next_nvpair(in_nvl, nvp)) {
6726e91bba0SGirish Moodalbail name = nvpair_name(nvp);
6736e91bba0SGirish Moodalbail if (!IPADM_PRIV_NVP(name) && nvlist_exists(db_nvl, name))
6746e91bba0SGirish Moodalbail break;
6756e91bba0SGirish Moodalbail }
6766e91bba0SGirish Moodalbail
6776e91bba0SGirish Moodalbail if (nvp == NULL)
6786e91bba0SGirish Moodalbail return (B_TRUE);
6796e91bba0SGirish Moodalbail
6806e91bba0SGirish Moodalbail assert(nvpair_type(nvp) == DATA_TYPE_STRING);
6816e91bba0SGirish Moodalbail
6826e91bba0SGirish Moodalbail if ((*errp = nvpair_value_string(nvp, &instrval)) != 0)
6836e91bba0SGirish Moodalbail return (B_FALSE);
6846e91bba0SGirish Moodalbail
6856e91bba0SGirish Moodalbail /*
6866e91bba0SGirish Moodalbail * If IPMGMT_APPEND is set then we are dealing with multi-valued
6876e91bba0SGirish Moodalbail * properties. We append to the entry from the db, with the new value.
6886e91bba0SGirish Moodalbail */
6896e91bba0SGirish Moodalbail if (flags & IPMGMT_APPEND) {
6906e91bba0SGirish Moodalbail if ((*errp = nvlist_lookup_string(db_nvl, name,
6916e91bba0SGirish Moodalbail &dbstrval)) != 0)
6926e91bba0SGirish Moodalbail return (B_FALSE);
6936e91bba0SGirish Moodalbail (void) snprintf(pval, MAXPROPVALLEN, "%s,%s", dbstrval,
6946e91bba0SGirish Moodalbail instrval);
6956e91bba0SGirish Moodalbail if ((*errp = nvlist_add_string(db_nvl, name, pval)) != 0)
6966e91bba0SGirish Moodalbail return (B_FALSE);
6976e91bba0SGirish Moodalbail } else {
6986e91bba0SGirish Moodalbail /* case of in-line update of a db entry */
6996e91bba0SGirish Moodalbail if ((*errp = nvlist_add_string(db_nvl, name, instrval)) != 0)
7006e91bba0SGirish Moodalbail return (B_FALSE);
7016e91bba0SGirish Moodalbail }
7026e91bba0SGirish Moodalbail
7036e91bba0SGirish Moodalbail (void) memset(buf, 0, buflen);
7046e91bba0SGirish Moodalbail if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
7056e91bba0SGirish Moodalbail /* buffer overflow */
7066e91bba0SGirish Moodalbail *errp = ENOBUFS;
7076e91bba0SGirish Moodalbail }
7086e91bba0SGirish Moodalbail
7096e91bba0SGirish Moodalbail /* we updated the DB entry, so do not continue */
7106e91bba0SGirish Moodalbail return (B_FALSE);
7116e91bba0SGirish Moodalbail }
7126e91bba0SGirish Moodalbail
7136e91bba0SGirish Moodalbail /*
714a73be61aSHans Rosenfeld * This function is used to update a DB line that describes
715a73be61aSHans Rosenfeld * an interface, its family and group interface
716a73be61aSHans Rosenfeld *
7176e91bba0SGirish Moodalbail */
7186e91bba0SGirish Moodalbail boolean_t
ipmgmt_db_update_if(void * arg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)719a73be61aSHans Rosenfeld ipmgmt_db_update_if(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
7206e91bba0SGirish Moodalbail int *errp)
7216e91bba0SGirish Moodalbail {
722a73be61aSHans Rosenfeld ipadm_dbwrite_cbarg_t *cb = arg;
723a73be61aSHans Rosenfeld ipmgmt_if_updater_ent_t *updater;
724a73be61aSHans Rosenfeld nvlist_t *in_nvl = cb->dbw_nvl;
725a73be61aSHans Rosenfeld uint_t flags = cb->dbw_flags;
726a73be61aSHans Rosenfeld nvpair_t *nvp;
727a73be61aSHans Rosenfeld char *name;
728a73be61aSHans Rosenfeld char *db_ifname;
729a73be61aSHans Rosenfeld char *gifname = NULL;
730a73be61aSHans Rosenfeld char *mifname = NULL;
7316e91bba0SGirish Moodalbail
7326e91bba0SGirish Moodalbail *errp = 0;
733a73be61aSHans Rosenfeld
734a73be61aSHans Rosenfeld /* Only one flag */
735a73be61aSHans Rosenfeld if ((flags & (IPMGMT_APPEND | IPMGMT_REMOVE)) == 0 ||
736a73be61aSHans Rosenfeld ((flags & IPMGMT_APPEND) && (flags & IPMGMT_REMOVE))) {
737a73be61aSHans Rosenfeld *errp = EINVAL;
738a73be61aSHans Rosenfeld return (B_FALSE);
739a73be61aSHans Rosenfeld }
740a73be61aSHans Rosenfeld
741a73be61aSHans Rosenfeld if (!nvlist_exists(db_nvl, IPADM_NVP_FAMILIES))
7426e91bba0SGirish Moodalbail return (B_TRUE);
743a73be61aSHans Rosenfeld
744a73be61aSHans Rosenfeld if (nvlist_exists(db_nvl, IPADM_NVP_IFCLASS) &&
745a73be61aSHans Rosenfeld nvlist_lookup_string(db_nvl, IPADM_NVP_IFNAME, &db_ifname) == 0 &&
746a73be61aSHans Rosenfeld nvlist_lookup_string(in_nvl, IPADM_NVP_GIFNAME, &gifname) == 0 &&
747a73be61aSHans Rosenfeld nvlist_lookup_string(in_nvl, IPADM_NVP_MIFNAMES, &mifname) == 0 &&
748a73be61aSHans Rosenfeld strcmp(db_ifname, mifname) == 0) {
749a73be61aSHans Rosenfeld if (flags & IPMGMT_APPEND) {
750a73be61aSHans Rosenfeld if ((*errp = nvlist_add_string(db_nvl,
751a73be61aSHans Rosenfeld IPADM_NVP_GIFNAME, gifname)) != 0)
752a73be61aSHans Rosenfeld return (B_FALSE);
753a73be61aSHans Rosenfeld } else {
754a73be61aSHans Rosenfeld if ((*errp = nvlist_remove(db_nvl, IPADM_NVP_GIFNAME,
755a73be61aSHans Rosenfeld DATA_TYPE_STRING)) != 0)
756a73be61aSHans Rosenfeld return (B_FALSE);
757a73be61aSHans Rosenfeld }
758a73be61aSHans Rosenfeld cb->dbw_flags &= ~IPMGMT_UPDATE_IPMP;
759a73be61aSHans Rosenfeld goto done;
7606e91bba0SGirish Moodalbail }
761a73be61aSHans Rosenfeld
762a73be61aSHans Rosenfeld if (!ipmgmt_nvlist_intersects(db_nvl, in_nvl))
763a73be61aSHans Rosenfeld return (B_TRUE);
764a73be61aSHans Rosenfeld
765a73be61aSHans Rosenfeld for (nvp = nvlist_next_nvpair(in_nvl, NULL); nvp != NULL;
766a73be61aSHans Rosenfeld nvp = nvlist_next_nvpair(in_nvl, nvp)) {
767a73be61aSHans Rosenfeld name = nvpair_name(nvp);
768a73be61aSHans Rosenfeld if (strcmp(name, IPADM_NVP_FAMILIES) != 0 &&
769a73be61aSHans Rosenfeld strcmp(name, IPADM_NVP_MIFNAMES) != 0)
770a73be61aSHans Rosenfeld continue;
771a73be61aSHans Rosenfeld
772a73be61aSHans Rosenfeld updater = ipmgmt_find_if_field_updater(name);
773a73be61aSHans Rosenfeld assert(updater != NULL);
774a73be61aSHans Rosenfeld *errp = (*updater->func)(db_nvl, nvp, flags);
775a73be61aSHans Rosenfeld if (*errp != 0)
776a73be61aSHans Rosenfeld return (B_FALSE);
7776e91bba0SGirish Moodalbail }
7786e91bba0SGirish Moodalbail
779a73be61aSHans Rosenfeld cb->dbw_flags &= ~IPMGMT_UPDATE_IF;
780a73be61aSHans Rosenfeld
781a73be61aSHans Rosenfeld done:
782a73be61aSHans Rosenfeld (void) memset(buf, 0, buflen);
783a73be61aSHans Rosenfeld if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
784a73be61aSHans Rosenfeld *errp = EOVERFLOW;
785a73be61aSHans Rosenfeld return (B_FALSE);
7866e91bba0SGirish Moodalbail }
7876e91bba0SGirish Moodalbail
788a73be61aSHans Rosenfeld /* we finished all operations, so do not continue */
789a73be61aSHans Rosenfeld if ((cb->dbw_flags & (IPMGMT_UPDATE_IF | IPMGMT_UPDATE_IPMP)) == 0)
790a73be61aSHans Rosenfeld return (B_FALSE);
791a73be61aSHans Rosenfeld
792a73be61aSHans Rosenfeld return (B_TRUE);
793a73be61aSHans Rosenfeld }
794a73be61aSHans Rosenfeld
795a73be61aSHans Rosenfeld /*
796a73be61aSHans Rosenfeld * For the given `cbarg->cb_ifname' interface, retrieve the nvlist that
797a73be61aSHans Rosenfeld * represents the persistent interface information.
798a73be61aSHans Rosenfeld * The nvlist contains:
799a73be61aSHans Rosenfeld * IPADM_NVP_IFNAME
800a73be61aSHans Rosenfeld * IPADM_NVP_FAMILIES
801a73be61aSHans Rosenfeld * IPADM_NVP_IF_CLASS
802a73be61aSHans Rosenfeld *
803a73be61aSHans Rosenfeld * (used in 'ipadm show-if')
804a73be61aSHans Rosenfeld */
805a73be61aSHans Rosenfeld /* ARGSUSED */
806a73be61aSHans Rosenfeld boolean_t
ipmgmt_db_getif(void * arg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)807a73be61aSHans Rosenfeld ipmgmt_db_getif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
808a73be61aSHans Rosenfeld int *errp)
809a73be61aSHans Rosenfeld {
810a73be61aSHans Rosenfeld ipmgmt_get_cbarg_t *cbarg = arg;
811a73be61aSHans Rosenfeld char *ifname = cbarg->cb_ifname;
812a73be61aSHans Rosenfeld nvpair_t *nvp;
813a73be61aSHans Rosenfeld char *db_ifname = NULL;
814a73be61aSHans Rosenfeld boolean_t families = B_FALSE;
815a73be61aSHans Rosenfeld
816a73be61aSHans Rosenfeld /* Parse db nvlist */
817a73be61aSHans Rosenfeld for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
818a73be61aSHans Rosenfeld nvp = nvlist_next_nvpair(db_nvl, nvp)) {
819a73be61aSHans Rosenfeld if (strcmp(nvpair_name(nvp), IPADM_NVP_IFNAME) == 0) {
820a73be61aSHans Rosenfeld (void) nvpair_value_string(nvp, &db_ifname);
821a73be61aSHans Rosenfeld } else if (strcmp(nvpair_name(nvp), IPADM_NVP_FAMILIES) == 0) {
822a73be61aSHans Rosenfeld families = B_TRUE;
823a73be61aSHans Rosenfeld }
8246e91bba0SGirish Moodalbail }
8256e91bba0SGirish Moodalbail
826a73be61aSHans Rosenfeld if (db_ifname == NULL || !families)
827a73be61aSHans Rosenfeld return (B_TRUE);
828a73be61aSHans Rosenfeld
829a73be61aSHans Rosenfeld if (ifname != NULL && ifname[0] != '\0' &&
830a73be61aSHans Rosenfeld strcmp(ifname, db_ifname) != 0)
831a73be61aSHans Rosenfeld return (B_TRUE);
832a73be61aSHans Rosenfeld
833a73be61aSHans Rosenfeld *errp = nvlist_add_nvlist(cbarg->cb_onvl, db_ifname, db_nvl);
834a73be61aSHans Rosenfeld if (*errp == 0)
835a73be61aSHans Rosenfeld cbarg->cb_ocnt++;
836a73be61aSHans Rosenfeld
837a73be61aSHans Rosenfeld if (ifname != NULL && ifname[0] != '\0')
8386e91bba0SGirish Moodalbail return (B_FALSE);
8396e91bba0SGirish Moodalbail
8406e91bba0SGirish Moodalbail return (B_TRUE);
8416e91bba0SGirish Moodalbail }
8426e91bba0SGirish Moodalbail
8436e91bba0SGirish Moodalbail /*
8446e91bba0SGirish Moodalbail * Deletes those entries from the database for which interface name
8456e91bba0SGirish Moodalbail * matches with the given `cbarg->cb_ifname'
8466e91bba0SGirish Moodalbail */
8476e91bba0SGirish Moodalbail /* ARGSUSED */
8486e91bba0SGirish Moodalbail boolean_t
ipmgmt_db_resetif(void * arg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)8496e91bba0SGirish Moodalbail ipmgmt_db_resetif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
8506e91bba0SGirish Moodalbail int *errp)
8516e91bba0SGirish Moodalbail {
8526e91bba0SGirish Moodalbail ipmgmt_if_cbarg_t *cbarg = arg;
8536e91bba0SGirish Moodalbail boolean_t isv6 = (cbarg->cb_family == AF_INET6);
8546e91bba0SGirish Moodalbail char *ifname = cbarg->cb_ifname;
8556e91bba0SGirish Moodalbail char *modstr = NULL;
8566e91bba0SGirish Moodalbail char *aobjname;
8576e91bba0SGirish Moodalbail uint_t proto;
8586e91bba0SGirish Moodalbail ipmgmt_aobjmap_t *head;
8596e91bba0SGirish Moodalbail boolean_t aobjfound = B_FALSE;
8606e91bba0SGirish Moodalbail
8616e91bba0SGirish Moodalbail *errp = 0;
8626e91bba0SGirish Moodalbail
8636e91bba0SGirish Moodalbail if (!ipmgmt_nvlist_contains(db_nvl, NULL, ifname, NULL))
8646e91bba0SGirish Moodalbail return (B_TRUE);
8656e91bba0SGirish Moodalbail
866a73be61aSHans Rosenfeld if (nvlist_exists(db_nvl, IPADM_NVP_FAMILIES)) {
867a73be61aSHans Rosenfeld
868a73be61aSHans Rosenfeld if ((*errp = ipmgmt_update_family_nvp(db_nvl, cbarg->cb_family,
869a73be61aSHans Rosenfeld IPMGMT_REMOVE)) != 0) {
870a73be61aSHans Rosenfeld return (B_FALSE);
871a73be61aSHans Rosenfeld }
872a73be61aSHans Rosenfeld
873a73be61aSHans Rosenfeld if (cbarg->cb_family == AF_INET) {
874a73be61aSHans Rosenfeld cbarg->cb_ipv4exists = B_FALSE;
875a73be61aSHans Rosenfeld } else {
876a73be61aSHans Rosenfeld assert(cbarg->cb_family == AF_INET6);
877a73be61aSHans Rosenfeld cbarg->cb_ipv6exists = B_FALSE;
878a73be61aSHans Rosenfeld }
879a73be61aSHans Rosenfeld if (!nvlist_exists(db_nvl, IPADM_NVP_FAMILIES)) {
880a73be61aSHans Rosenfeld cbarg->cb_ipv4exists = B_FALSE;
881a73be61aSHans Rosenfeld cbarg->cb_ipv6exists = B_FALSE;
8826e91bba0SGirish Moodalbail goto delete;
883a73be61aSHans Rosenfeld }
884a73be61aSHans Rosenfeld /* Otherwise need to reconstruct this string */
885a73be61aSHans Rosenfeld (void) memset(buf, 0, buflen);
886a73be61aSHans Rosenfeld if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
887a73be61aSHans Rosenfeld /* buffer overflow */
888a73be61aSHans Rosenfeld *errp = EOVERFLOW;
889a73be61aSHans Rosenfeld return (B_FALSE);
890a73be61aSHans Rosenfeld }
8916e91bba0SGirish Moodalbail return (B_TRUE);
8926e91bba0SGirish Moodalbail }
8936e91bba0SGirish Moodalbail
8946e91bba0SGirish Moodalbail /* Reset all the interface configurations for 'ifname' */
8956e91bba0SGirish Moodalbail if (isv6 && (nvlist_exists(db_nvl, IPADM_NVP_IPV6ADDR) ||
8966e91bba0SGirish Moodalbail nvlist_exists(db_nvl, IPADM_NVP_INTFID))) {
8976e91bba0SGirish Moodalbail goto delete;
8986e91bba0SGirish Moodalbail }
8996e91bba0SGirish Moodalbail if (!isv6 &&
9006e91bba0SGirish Moodalbail (nvlist_exists(db_nvl, IPADM_NVP_IPV4ADDR) ||
9016e91bba0SGirish Moodalbail nvlist_exists(db_nvl, IPADM_NVP_DHCP))) {
9026e91bba0SGirish Moodalbail goto delete;
9036e91bba0SGirish Moodalbail }
9046e91bba0SGirish Moodalbail
9056e91bba0SGirish Moodalbail if (nvlist_lookup_string(db_nvl, IPADM_NVP_AOBJNAME, &aobjname) == 0) {
9066e91bba0SGirish Moodalbail /*
9076e91bba0SGirish Moodalbail * This must be an address property. Delete this
9086e91bba0SGirish Moodalbail * line if there is a match in the address family.
9096e91bba0SGirish Moodalbail */
9106e91bba0SGirish Moodalbail head = aobjmap.aobjmap_head;
9116e91bba0SGirish Moodalbail while (head != NULL) {
9126e91bba0SGirish Moodalbail if (strcmp(head->am_aobjname, aobjname) == 0) {
9136e91bba0SGirish Moodalbail aobjfound = B_TRUE;
9146e91bba0SGirish Moodalbail if (head->am_family == cbarg->cb_family)
9156e91bba0SGirish Moodalbail goto delete;
9166e91bba0SGirish Moodalbail }
9176e91bba0SGirish Moodalbail head = head->am_next;
9186e91bba0SGirish Moodalbail }
9196e91bba0SGirish Moodalbail /*
9206e91bba0SGirish Moodalbail * If aobjfound = B_FALSE, then this address is not
9216e91bba0SGirish Moodalbail * available in active configuration. We should go ahead
9226e91bba0SGirish Moodalbail * and delete it.
9236e91bba0SGirish Moodalbail */
9246e91bba0SGirish Moodalbail if (!aobjfound)
9256e91bba0SGirish Moodalbail goto delete;
9266e91bba0SGirish Moodalbail }
9276e91bba0SGirish Moodalbail
9286e91bba0SGirish Moodalbail /*
9296e91bba0SGirish Moodalbail * If we are removing both v4 and v6 interface, then we get rid of
9306e91bba0SGirish Moodalbail * all the properties for that interface. On the other hand, if we
9316e91bba0SGirish Moodalbail * are deleting only v4 instance of an interface, then we delete v4
9326e91bba0SGirish Moodalbail * properties only.
9336e91bba0SGirish Moodalbail */
9346e91bba0SGirish Moodalbail if (nvlist_lookup_string(db_nvl, IPADM_NVP_PROTONAME, &modstr) == 0) {
9356e91bba0SGirish Moodalbail proto = ipadm_str2proto(modstr);
9366e91bba0SGirish Moodalbail switch (proto) {
9376e91bba0SGirish Moodalbail case MOD_PROTO_IPV6:
9386e91bba0SGirish Moodalbail if (isv6)
9396e91bba0SGirish Moodalbail goto delete;
9406e91bba0SGirish Moodalbail break;
9416e91bba0SGirish Moodalbail case MOD_PROTO_IPV4:
9426e91bba0SGirish Moodalbail if (!isv6)
9436e91bba0SGirish Moodalbail goto delete;
9446e91bba0SGirish Moodalbail break;
9456e91bba0SGirish Moodalbail case MOD_PROTO_IP:
946a73be61aSHans Rosenfeld if (!cbarg->cb_ipv4exists && !cbarg->cb_ipv6exists)
947a73be61aSHans Rosenfeld goto delete;
9486e91bba0SGirish Moodalbail break;
9496e91bba0SGirish Moodalbail }
9506e91bba0SGirish Moodalbail }
9516e91bba0SGirish Moodalbail /* Not found a match yet. Continue processing the db */
9526e91bba0SGirish Moodalbail return (B_TRUE);
9536e91bba0SGirish Moodalbail delete:
9546e91bba0SGirish Moodalbail /* delete the line from the db */
9556e91bba0SGirish Moodalbail buf[0] = '\0';
9566e91bba0SGirish Moodalbail return (B_TRUE);
9576e91bba0SGirish Moodalbail }
9586e91bba0SGirish Moodalbail
9596e91bba0SGirish Moodalbail /*
9606e91bba0SGirish Moodalbail * Deletes those entries from the database for which address object name
9616e91bba0SGirish Moodalbail * matches with the given `cbarg->cb_aobjname'
9626e91bba0SGirish Moodalbail */
9636e91bba0SGirish Moodalbail /* ARGSUSED */
9646e91bba0SGirish Moodalbail boolean_t
ipmgmt_db_resetaddr(void * arg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)9656e91bba0SGirish Moodalbail ipmgmt_db_resetaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
9666e91bba0SGirish Moodalbail int *errp)
9676e91bba0SGirish Moodalbail {
9686e91bba0SGirish Moodalbail ipmgmt_resetaddr_cbarg_t *cbarg = arg;
9696e91bba0SGirish Moodalbail char *aobjname = cbarg->cb_aobjname;
9706e91bba0SGirish Moodalbail
9716e91bba0SGirish Moodalbail *errp = 0;
9726e91bba0SGirish Moodalbail if (!ipmgmt_nvlist_contains(db_nvl, NULL, NULL, aobjname))
9736e91bba0SGirish Moodalbail return (B_TRUE);
9746e91bba0SGirish Moodalbail
9756e91bba0SGirish Moodalbail /* delete the line from the db */
9766e91bba0SGirish Moodalbail buf[0] = '\0';
9776e91bba0SGirish Moodalbail return (B_TRUE);
9786e91bba0SGirish Moodalbail }
9796e91bba0SGirish Moodalbail
9806e91bba0SGirish Moodalbail /*
9816e91bba0SGirish Moodalbail * Retrieves all interface props, including addresses, for given interface(s).
9826e91bba0SGirish Moodalbail * `invl' contains the list of interfaces, for which information need to be
9836e91bba0SGirish Moodalbail * retrieved.
9846e91bba0SGirish Moodalbail */
9856e91bba0SGirish Moodalbail /* ARGSUSED */
9866e91bba0SGirish Moodalbail boolean_t
ipmgmt_db_initif(void * arg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)9876e91bba0SGirish Moodalbail ipmgmt_db_initif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
9886e91bba0SGirish Moodalbail int *errp)
9896e91bba0SGirish Moodalbail {
9906e91bba0SGirish Moodalbail ipmgmt_initif_cbarg_t *cbarg = arg;
9916e91bba0SGirish Moodalbail nvlist_t *onvl = cbarg->cb_onvl;
9926e91bba0SGirish Moodalbail nvlist_t *invl = cbarg->cb_invl;
9936e91bba0SGirish Moodalbail sa_family_t in_af = cbarg->cb_family;
9946e91bba0SGirish Moodalbail char *db_ifname;
9956e91bba0SGirish Moodalbail
9966e91bba0SGirish Moodalbail *errp = 0;
9976e91bba0SGirish Moodalbail if (nvlist_lookup_string(db_nvl, IPADM_NVP_IFNAME, &db_ifname) == 0 &&
9986e91bba0SGirish Moodalbail nvlist_exists(invl, db_ifname)) {
9996e91bba0SGirish Moodalbail char name[IPMGMT_STRSIZE];
10006e91bba0SGirish Moodalbail sa_family_t db_af = in_af;
10016e91bba0SGirish Moodalbail uint_t proto;
10026e91bba0SGirish Moodalbail char *pstr;
10036e91bba0SGirish Moodalbail
10046e91bba0SGirish Moodalbail if (in_af != AF_UNSPEC) {
10056e91bba0SGirish Moodalbail if (nvlist_lookup_string(db_nvl, IPADM_NVP_PROTONAME,
10066e91bba0SGirish Moodalbail &pstr) == 0) {
10076e91bba0SGirish Moodalbail proto = ipadm_str2proto(pstr);
10086e91bba0SGirish Moodalbail if (proto == MOD_PROTO_IPV4)
10096e91bba0SGirish Moodalbail db_af = AF_INET;
10106e91bba0SGirish Moodalbail else if (proto == MOD_PROTO_IPV6)
10116e91bba0SGirish Moodalbail db_af = AF_INET6;
10126e91bba0SGirish Moodalbail else
10136e91bba0SGirish Moodalbail db_af = in_af;
10146e91bba0SGirish Moodalbail } else {
10156e91bba0SGirish Moodalbail if (nvlist_exists(db_nvl, IPADM_NVP_IPV4ADDR) ||
10166e91bba0SGirish Moodalbail nvlist_exists(db_nvl, IPADM_NVP_DHCP))
10176e91bba0SGirish Moodalbail db_af = AF_INET;
10186e91bba0SGirish Moodalbail else
10196e91bba0SGirish Moodalbail db_af = AF_INET6;
10206e91bba0SGirish Moodalbail }
10216e91bba0SGirish Moodalbail }
10226e91bba0SGirish Moodalbail if (in_af == db_af) {
10236e91bba0SGirish Moodalbail (void) snprintf(name, sizeof (name), "%s_%d", db_ifname,
10246e91bba0SGirish Moodalbail cbarg->cb_ocnt);
10256e91bba0SGirish Moodalbail *errp = nvlist_add_nvlist(onvl, name, db_nvl);
10266e91bba0SGirish Moodalbail if (*errp == 0)
10276e91bba0SGirish Moodalbail cbarg->cb_ocnt++;
10286e91bba0SGirish Moodalbail }
10296e91bba0SGirish Moodalbail }
10306e91bba0SGirish Moodalbail return (B_TRUE);
10316e91bba0SGirish Moodalbail }
10326e91bba0SGirish Moodalbail
10336e91bba0SGirish Moodalbail /*
10346e91bba0SGirish Moodalbail * helper function for ipmgmt_aobjmap_op(). Adds the node pointed by `nodep'
10356e91bba0SGirish Moodalbail * into `aobjmap' structure.
10366e91bba0SGirish Moodalbail */
10376e91bba0SGirish Moodalbail static int
i_ipmgmt_add_amnode(ipmgmt_aobjmap_t * nodep)10386e91bba0SGirish Moodalbail i_ipmgmt_add_amnode(ipmgmt_aobjmap_t *nodep)
10396e91bba0SGirish Moodalbail {
10406e91bba0SGirish Moodalbail ipmgmt_aobjmap_t *new, *head;
10416e91bba0SGirish Moodalbail
10426e91bba0SGirish Moodalbail head = aobjmap.aobjmap_head;
10436e91bba0SGirish Moodalbail if ((new = malloc(sizeof (ipmgmt_aobjmap_t))) == NULL)
10446e91bba0SGirish Moodalbail return (ENOMEM);
10456e91bba0SGirish Moodalbail *new = *nodep;
10466e91bba0SGirish Moodalbail new->am_next = NULL;
10476e91bba0SGirish Moodalbail
10486e91bba0SGirish Moodalbail /* Add the node at the beginning of the list */
10496e91bba0SGirish Moodalbail if (head == NULL) {
10506e91bba0SGirish Moodalbail aobjmap.aobjmap_head = new;
10516e91bba0SGirish Moodalbail } else {
10526e91bba0SGirish Moodalbail new->am_next = aobjmap.aobjmap_head;
10536e91bba0SGirish Moodalbail aobjmap.aobjmap_head = new;
10546e91bba0SGirish Moodalbail }
10556e91bba0SGirish Moodalbail return (0);
10566e91bba0SGirish Moodalbail }
10576e91bba0SGirish Moodalbail
10586e91bba0SGirish Moodalbail /*
10596e91bba0SGirish Moodalbail * A recursive function to generate alphabetized number given a decimal number.
10606e91bba0SGirish Moodalbail * Decimal 0 to 25 maps to 'a' to 'z' and then the counting continues with 'aa',
10616e91bba0SGirish Moodalbail * 'ab', 'ac', et al.
10626e91bba0SGirish Moodalbail */
10636e91bba0SGirish Moodalbail static void
i_ipmgmt_num2priv_aobjname(uint32_t num,char ** cp,char * endp)10646e91bba0SGirish Moodalbail i_ipmgmt_num2priv_aobjname(uint32_t num, char **cp, char *endp)
10656e91bba0SGirish Moodalbail {
10666e91bba0SGirish Moodalbail if (num >= 26)
10676e91bba0SGirish Moodalbail i_ipmgmt_num2priv_aobjname(num / 26 - 1, cp, endp);
10686e91bba0SGirish Moodalbail if (*cp != endp) {
10696e91bba0SGirish Moodalbail *cp[0] = 'a' + (num % 26);
10706e91bba0SGirish Moodalbail (*cp)++;
10716e91bba0SGirish Moodalbail }
10726e91bba0SGirish Moodalbail }
10736e91bba0SGirish Moodalbail
10746e91bba0SGirish Moodalbail /*
10756e91bba0SGirish Moodalbail * This function generates an `aobjname', when required, and then does
10766e91bba0SGirish Moodalbail * lookup-add. If `nodep->am_aobjname' is not an empty string, then it walks
10776e91bba0SGirish Moodalbail * through the `aobjmap' to check if an address object with the same
10786e91bba0SGirish Moodalbail * `nodep->am_aobjname' exists. If it exists, EEXIST is returned as duplicate
10796e91bba0SGirish Moodalbail * `aobjname's are not allowed.
10806e91bba0SGirish Moodalbail *
10816e91bba0SGirish Moodalbail * If `nodep->am_aobjname' is an empty string then the daemon generates an
10826e91bba0SGirish Moodalbail * `aobjname' using the `am_nextnum', which contains the next number to be
10836e91bba0SGirish Moodalbail * used to generate `aobjname'. `am_nextnum' is converted to base26 using
10846e91bba0SGirish Moodalbail * `a-z' alphabets in i_ipmgmt_num2priv_aobjname().
10856e91bba0SGirish Moodalbail *
10866e91bba0SGirish Moodalbail * `am_nextnum' will be 0 to begin with. Every time an address object that
10876e91bba0SGirish Moodalbail * needs `aobjname' is added it's incremented by 1. So for the first address
10886e91bba0SGirish Moodalbail * object on net0 the `am_aobjname' will be net0/_a and `am_nextnum' will be 1.
10896e91bba0SGirish Moodalbail * For the second address object on that interface `am_aobjname' will be net0/_b
10906e91bba0SGirish Moodalbail * and `am_nextnum' will incremented to 2.
10916e91bba0SGirish Moodalbail */
10926e91bba0SGirish Moodalbail static int
i_ipmgmt_lookupadd_amnode(ipmgmt_aobjmap_t * nodep)10936e91bba0SGirish Moodalbail i_ipmgmt_lookupadd_amnode(ipmgmt_aobjmap_t *nodep)
10946e91bba0SGirish Moodalbail {
10956e91bba0SGirish Moodalbail ipmgmt_aobjmap_t *head;
10966e91bba0SGirish Moodalbail uint32_t nextnum;
10976e91bba0SGirish Moodalbail
10986e91bba0SGirish Moodalbail for (head = aobjmap.aobjmap_head; head != NULL; head = head->am_next)
10996e91bba0SGirish Moodalbail if (strcmp(head->am_ifname, nodep->am_ifname) == 0)
11006e91bba0SGirish Moodalbail break;
11016e91bba0SGirish Moodalbail nextnum = (head == NULL ? 0 : head->am_nextnum);
11026e91bba0SGirish Moodalbail
11036e91bba0SGirish Moodalbail /*
11046e91bba0SGirish Moodalbail * if `aobjname' is empty, then the daemon has to generate the
11056e91bba0SGirish Moodalbail * next `aobjname' for the given interface and family.
11066e91bba0SGirish Moodalbail */
11076e91bba0SGirish Moodalbail if (nodep->am_aobjname[0] == '\0') {
11086e91bba0SGirish Moodalbail char tmpstr[IPADM_AOBJ_USTRSIZ - 1]; /* 1 for leading '_' */
11096e91bba0SGirish Moodalbail char *cp = tmpstr;
11106e91bba0SGirish Moodalbail char *endp = tmpstr + sizeof (tmpstr);
11116e91bba0SGirish Moodalbail
11126e91bba0SGirish Moodalbail i_ipmgmt_num2priv_aobjname(nextnum, &cp, endp);
11136e91bba0SGirish Moodalbail
11146e91bba0SGirish Moodalbail if (cp == endp)
11156e91bba0SGirish Moodalbail return (EINVAL);
11166e91bba0SGirish Moodalbail cp[0] = '\0';
11176e91bba0SGirish Moodalbail
11186e91bba0SGirish Moodalbail if (snprintf(nodep->am_aobjname, IPADM_AOBJSIZ, "%s/_%s",
11196e91bba0SGirish Moodalbail nodep->am_ifname, tmpstr) >= IPADM_AOBJSIZ) {
11206e91bba0SGirish Moodalbail return (EINVAL);
11216e91bba0SGirish Moodalbail }
11226e91bba0SGirish Moodalbail nodep->am_nextnum = ++nextnum;
11236e91bba0SGirish Moodalbail } else {
11246e91bba0SGirish Moodalbail for (head = aobjmap.aobjmap_head; head != NULL;
11256e91bba0SGirish Moodalbail head = head->am_next) {
11266e91bba0SGirish Moodalbail if (strcmp(head->am_aobjname, nodep->am_aobjname) == 0)
11276e91bba0SGirish Moodalbail return (EEXIST);
11286e91bba0SGirish Moodalbail }
11296e91bba0SGirish Moodalbail nodep->am_nextnum = nextnum;
11306e91bba0SGirish Moodalbail }
11316e91bba0SGirish Moodalbail return (i_ipmgmt_add_amnode(nodep));
11326e91bba0SGirish Moodalbail }
11336e91bba0SGirish Moodalbail
11346e91bba0SGirish Moodalbail /*
11356e91bba0SGirish Moodalbail * Performs following operations on the global `aobjmap' linked list.
11366e91bba0SGirish Moodalbail * (a) ADDROBJ_ADD: add or update address object in `aobjmap'
11376e91bba0SGirish Moodalbail * (b) ADDROBJ_DELETE: delete address object from `aobjmap'
11386e91bba0SGirish Moodalbail * (c) ADDROBJ_LOOKUPADD: place a stub address object in `aobjmap'
1139ec3706caSVasumathi Sundaram * (d) ADDROBJ_SETLIFNUM: Sets the lifnum for an address object in `aobjmap'
11406e91bba0SGirish Moodalbail */
11416e91bba0SGirish Moodalbail int
ipmgmt_aobjmap_op(ipmgmt_aobjmap_t * nodep,uint32_t op)11426e91bba0SGirish Moodalbail ipmgmt_aobjmap_op(ipmgmt_aobjmap_t *nodep, uint32_t op)
11436e91bba0SGirish Moodalbail {
1144ec3706caSVasumathi Sundaram ipmgmt_aobjmap_t *head, *prev, *matched = NULL;
11456e91bba0SGirish Moodalbail boolean_t update = B_TRUE;
11466e91bba0SGirish Moodalbail int err = 0;
1147a73be61aSHans Rosenfeld ipadm_db_op_t db_op = IPADM_DB_READ;
11486e91bba0SGirish Moodalbail
11496e91bba0SGirish Moodalbail (void) pthread_rwlock_wrlock(&aobjmap.aobjmap_rwlock);
11506e91bba0SGirish Moodalbail
11516e91bba0SGirish Moodalbail head = aobjmap.aobjmap_head;
11526e91bba0SGirish Moodalbail switch (op) {
11536e91bba0SGirish Moodalbail case ADDROBJ_ADD:
11546e91bba0SGirish Moodalbail /*
11556e91bba0SGirish Moodalbail * check for stub nodes (added by ADDROBJ_LOOKUPADD) and
11566e91bba0SGirish Moodalbail * update, else add the new node.
11576e91bba0SGirish Moodalbail */
11586e91bba0SGirish Moodalbail for (; head != NULL; head = head->am_next) {
1159ec3706caSVasumathi Sundaram /*
1160ec3706caSVasumathi Sundaram * For IPv6, we need to distinguish between the
1161ec3706caSVasumathi Sundaram * linklocal and non-linklocal nodes
1162ec3706caSVasumathi Sundaram */
11636e91bba0SGirish Moodalbail if (strcmp(head->am_aobjname,
1164ec3706caSVasumathi Sundaram nodep->am_aobjname) == 0 &&
1165ec3706caSVasumathi Sundaram (head->am_atype != IPADM_ADDR_IPV6_ADDRCONF ||
1166b31320a7SChris Fraire head->ipmgmt_am_linklocal ==
1167b31320a7SChris Fraire nodep->ipmgmt_am_linklocal))
11686e91bba0SGirish Moodalbail break;
11696e91bba0SGirish Moodalbail }
11706e91bba0SGirish Moodalbail
11716e91bba0SGirish Moodalbail if (head != NULL) {
11726e91bba0SGirish Moodalbail /* update the node */
11736e91bba0SGirish Moodalbail (void) strlcpy(head->am_ifname, nodep->am_ifname,
11746e91bba0SGirish Moodalbail sizeof (head->am_ifname));
11756e91bba0SGirish Moodalbail head->am_lnum = nodep->am_lnum;
11766e91bba0SGirish Moodalbail head->am_family = nodep->am_family;
11776e91bba0SGirish Moodalbail head->am_flags = nodep->am_flags;
11786e91bba0SGirish Moodalbail head->am_atype = nodep->am_atype;
1179b31320a7SChris Fraire head->am_atype_cache = nodep->am_atype_cache;
11806e91bba0SGirish Moodalbail } else {
11816e91bba0SGirish Moodalbail for (head = aobjmap.aobjmap_head; head != NULL;
11826e91bba0SGirish Moodalbail head = head->am_next) {
11836e91bba0SGirish Moodalbail if (strcmp(head->am_ifname,
11846e91bba0SGirish Moodalbail nodep->am_ifname) == 0)
11856e91bba0SGirish Moodalbail break;
11866e91bba0SGirish Moodalbail }
11876e91bba0SGirish Moodalbail nodep->am_nextnum = (head == NULL ? 0 :
11886e91bba0SGirish Moodalbail head->am_nextnum);
11896e91bba0SGirish Moodalbail err = i_ipmgmt_add_amnode(nodep);
11906e91bba0SGirish Moodalbail }
11916e91bba0SGirish Moodalbail db_op = IPADM_DB_WRITE;
11926e91bba0SGirish Moodalbail break;
11936e91bba0SGirish Moodalbail case ADDROBJ_DELETE:
11946e91bba0SGirish Moodalbail prev = head;
11956e91bba0SGirish Moodalbail while (head != NULL) {
11966e91bba0SGirish Moodalbail if (strcmp(head->am_aobjname,
11976e91bba0SGirish Moodalbail nodep->am_aobjname) == 0) {
11986e91bba0SGirish Moodalbail nodep->am_atype = head->am_atype;
11996e91bba0SGirish Moodalbail /*
12006e91bba0SGirish Moodalbail * There could be multiple IPV6_ADDRCONF nodes,
12016e91bba0SGirish Moodalbail * with same address object name, so check for
12026e91bba0SGirish Moodalbail * logical number also.
12036e91bba0SGirish Moodalbail */
12046e91bba0SGirish Moodalbail if (head->am_atype !=
12056e91bba0SGirish Moodalbail IPADM_ADDR_IPV6_ADDRCONF ||
12066e91bba0SGirish Moodalbail nodep->am_lnum == head->am_lnum)
12076e91bba0SGirish Moodalbail break;
12086e91bba0SGirish Moodalbail }
12096e91bba0SGirish Moodalbail prev = head;
12106e91bba0SGirish Moodalbail head = head->am_next;
12116e91bba0SGirish Moodalbail }
12126e91bba0SGirish Moodalbail if (head != NULL) {
12136e91bba0SGirish Moodalbail /*
12146e91bba0SGirish Moodalbail * If the address object is in both active and
12156e91bba0SGirish Moodalbail * persistent configuration and the user is deleting it
12166e91bba0SGirish Moodalbail * only from active configuration then mark this node
12176e91bba0SGirish Moodalbail * for deletion by reseting IPMGMT_ACTIVE bit.
12186e91bba0SGirish Moodalbail * With this the same address object name cannot
12196e91bba0SGirish Moodalbail * be reused until it is permanently removed.
12206e91bba0SGirish Moodalbail */
12216e91bba0SGirish Moodalbail if (head->am_flags == (IPMGMT_ACTIVE|IPMGMT_PERSIST) &&
12226e91bba0SGirish Moodalbail nodep->am_flags == IPMGMT_ACTIVE) {
12236e91bba0SGirish Moodalbail /* Update flags in the in-memory map. */
12246e91bba0SGirish Moodalbail head->am_flags &= ~IPMGMT_ACTIVE;
12256e91bba0SGirish Moodalbail head->am_lnum = -1;
12266e91bba0SGirish Moodalbail
12276e91bba0SGirish Moodalbail /* Update info in file. */
12286e91bba0SGirish Moodalbail db_op = IPADM_DB_WRITE;
12296e91bba0SGirish Moodalbail *nodep = *head;
12306e91bba0SGirish Moodalbail } else {
12316e91bba0SGirish Moodalbail (void) strlcpy(nodep->am_ifname,
12326e91bba0SGirish Moodalbail head->am_ifname,
12336e91bba0SGirish Moodalbail sizeof (nodep->am_ifname));
12346e91bba0SGirish Moodalbail /* otherwise delete the node */
12356e91bba0SGirish Moodalbail if (head == aobjmap.aobjmap_head)
12366e91bba0SGirish Moodalbail aobjmap.aobjmap_head = head->am_next;
12376e91bba0SGirish Moodalbail else
12386e91bba0SGirish Moodalbail prev->am_next = head->am_next;
12396e91bba0SGirish Moodalbail free(head);
12406e91bba0SGirish Moodalbail db_op = IPADM_DB_DELETE;
12416e91bba0SGirish Moodalbail }
12426e91bba0SGirish Moodalbail } else {
12436e91bba0SGirish Moodalbail err = ENOENT;
12446e91bba0SGirish Moodalbail }
12456e91bba0SGirish Moodalbail break;
12466e91bba0SGirish Moodalbail case ADDROBJ_LOOKUPADD:
12476e91bba0SGirish Moodalbail err = i_ipmgmt_lookupadd_amnode(nodep);
12486e91bba0SGirish Moodalbail update = B_FALSE;
12496e91bba0SGirish Moodalbail break;
1250ec3706caSVasumathi Sundaram case ADDROBJ_SETLIFNUM:
1251ec3706caSVasumathi Sundaram update = B_FALSE;
1252ec3706caSVasumathi Sundaram for (; head != NULL; head = head->am_next) {
1253ec3706caSVasumathi Sundaram if (strcmp(head->am_ifname,
1254ec3706caSVasumathi Sundaram nodep->am_ifname) == 0 &&
1255ec3706caSVasumathi Sundaram head->am_family == nodep->am_family &&
1256ec3706caSVasumathi Sundaram head->am_lnum == nodep->am_lnum) {
1257ec3706caSVasumathi Sundaram err = EEXIST;
1258ec3706caSVasumathi Sundaram break;
1259ec3706caSVasumathi Sundaram }
1260ec3706caSVasumathi Sundaram if (strcmp(head->am_aobjname,
1261ec3706caSVasumathi Sundaram nodep->am_aobjname) == 0) {
1262ec3706caSVasumathi Sundaram matched = head;
1263ec3706caSVasumathi Sundaram }
1264ec3706caSVasumathi Sundaram }
1265ec3706caSVasumathi Sundaram if (err == EEXIST)
1266ec3706caSVasumathi Sundaram break;
1267ec3706caSVasumathi Sundaram if (matched != NULL) {
1268ec3706caSVasumathi Sundaram /* update the lifnum */
1269ec3706caSVasumathi Sundaram matched->am_lnum = nodep->am_lnum;
1270ec3706caSVasumathi Sundaram } else {
1271ec3706caSVasumathi Sundaram err = ENOENT;
1272ec3706caSVasumathi Sundaram }
1273ec3706caSVasumathi Sundaram break;
12746e91bba0SGirish Moodalbail default:
12756e91bba0SGirish Moodalbail assert(0);
12766e91bba0SGirish Moodalbail }
12776e91bba0SGirish Moodalbail
12786e91bba0SGirish Moodalbail if (err == 0 && update)
12796e91bba0SGirish Moodalbail err = ipmgmt_persist_aobjmap(nodep, db_op);
12806e91bba0SGirish Moodalbail
12816e91bba0SGirish Moodalbail (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
12826e91bba0SGirish Moodalbail
12836e91bba0SGirish Moodalbail return (err);
12846e91bba0SGirish Moodalbail }
12856e91bba0SGirish Moodalbail
12866e91bba0SGirish Moodalbail /*
12876e91bba0SGirish Moodalbail * Given a node in `aobjmap', this function converts it into nvlist_t structure.
12886e91bba0SGirish Moodalbail * The content to be written to DB must be represented as nvlist_t.
12896e91bba0SGirish Moodalbail */
12906e91bba0SGirish Moodalbail static int
i_ipmgmt_node2nvl(nvlist_t ** nvl,ipmgmt_aobjmap_t * np)12916e91bba0SGirish Moodalbail i_ipmgmt_node2nvl(nvlist_t **nvl, ipmgmt_aobjmap_t *np)
12926e91bba0SGirish Moodalbail {
12936e91bba0SGirish Moodalbail int err;
12946e91bba0SGirish Moodalbail char strval[IPMGMT_STRSIZE];
12956e91bba0SGirish Moodalbail
12966e91bba0SGirish Moodalbail *nvl = NULL;
12976e91bba0SGirish Moodalbail if ((err = nvlist_alloc(nvl, NV_UNIQUE_NAME, 0)) != 0)
12986e91bba0SGirish Moodalbail goto fail;
12996e91bba0SGirish Moodalbail
13006e91bba0SGirish Moodalbail if ((err = nvlist_add_string(*nvl, IPADM_NVP_AOBJNAME,
13016e91bba0SGirish Moodalbail np->am_aobjname)) != 0)
13026e91bba0SGirish Moodalbail goto fail;
13036e91bba0SGirish Moodalbail
13046e91bba0SGirish Moodalbail if ((err = nvlist_add_string(*nvl, IPADM_NVP_IFNAME,
13056e91bba0SGirish Moodalbail np->am_ifname)) != 0)
13066e91bba0SGirish Moodalbail goto fail;
13076e91bba0SGirish Moodalbail
13086e91bba0SGirish Moodalbail (void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_lnum);
13096e91bba0SGirish Moodalbail if ((err = nvlist_add_string(*nvl, IPADM_NVP_LIFNUM, strval)) != 0)
13106e91bba0SGirish Moodalbail goto fail;
13116e91bba0SGirish Moodalbail
13126e91bba0SGirish Moodalbail (void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_family);
13136e91bba0SGirish Moodalbail if ((err = nvlist_add_string(*nvl, IPADM_NVP_FAMILY, strval)) != 0)
13146e91bba0SGirish Moodalbail goto fail;
13156e91bba0SGirish Moodalbail
13166e91bba0SGirish Moodalbail (void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_flags);
13176e91bba0SGirish Moodalbail if ((err = nvlist_add_string(*nvl, FLAGS, strval)) != 0)
13186e91bba0SGirish Moodalbail goto fail;
13196e91bba0SGirish Moodalbail
13206e91bba0SGirish Moodalbail (void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_atype);
13216e91bba0SGirish Moodalbail if ((err = nvlist_add_string(*nvl, ATYPE, strval)) != 0)
13226e91bba0SGirish Moodalbail goto fail;
13236e91bba0SGirish Moodalbail
1324b31320a7SChris Fraire switch (np->am_atype) {
1325b31320a7SChris Fraire case IPADM_ADDR_IPV6_ADDRCONF: {
1326b31320a7SChris Fraire struct sockaddr_in6 *in6;
13276e91bba0SGirish Moodalbail
1328b31320a7SChris Fraire in6 = &np->ipmgmt_am_ifid;
1329b31320a7SChris Fraire if (np->ipmgmt_am_linklocal &&
1330b31320a7SChris Fraire IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr)) {
1331b31320a7SChris Fraire if ((err = nvlist_add_string(*nvl,
1332b31320a7SChris Fraire IPADM_NVP_IPNUMADDR, "default")) != 0) {
1333b31320a7SChris Fraire goto fail;
1334b31320a7SChris Fraire }
1335b31320a7SChris Fraire } else {
1336b31320a7SChris Fraire if (inet_ntop(AF_INET6, &in6->sin6_addr, strval,
1337b31320a7SChris Fraire IPMGMT_STRSIZE) == NULL) {
1338b31320a7SChris Fraire err = errno;
1339b31320a7SChris Fraire goto fail;
1340b31320a7SChris Fraire }
1341b31320a7SChris Fraire if ((err = nvlist_add_string(*nvl,
1342b31320a7SChris Fraire IPADM_NVP_IPNUMADDR, strval)) != 0) {
1343b31320a7SChris Fraire goto fail;
1344b31320a7SChris Fraire }
13456e91bba0SGirish Moodalbail }
1346b31320a7SChris Fraire }
1347b31320a7SChris Fraire break;
1348b31320a7SChris Fraire case IPADM_ADDR_DHCP: {
1349*924ac941SToomas Soome if (*np->ipmgmt_am_reqhost != '\0' &&
1350b31320a7SChris Fraire (err = nvlist_add_string(*nvl, IPADM_NVP_REQHOST,
1351b31320a7SChris Fraire np->ipmgmt_am_reqhost)) != 0)
13526e91bba0SGirish Moodalbail goto fail;
13536e91bba0SGirish Moodalbail }
1354b31320a7SChris Fraire /* FALLTHRU */
1355b31320a7SChris Fraire default:
1356b31320a7SChris Fraire if ((err = nvlist_add_string(*nvl, IPADM_NVP_IPNUMADDR,
1357b31320a7SChris Fraire "")) != 0)
1358b31320a7SChris Fraire goto fail;
1359b31320a7SChris Fraire break;
13606e91bba0SGirish Moodalbail }
13616e91bba0SGirish Moodalbail return (err);
13626e91bba0SGirish Moodalbail fail:
13636e91bba0SGirish Moodalbail nvlist_free(*nvl);
13646e91bba0SGirish Moodalbail return (err);
13656e91bba0SGirish Moodalbail }
13666e91bba0SGirish Moodalbail
13676e91bba0SGirish Moodalbail /*
13686e91bba0SGirish Moodalbail * Read the aobjmap data store and build the in-memory representation
13696e91bba0SGirish Moodalbail * of the aobjmap. We don't need to hold any locks while building this as
13706e91bba0SGirish Moodalbail * we do this in very early stage of daemon coming up, even before the door
13716e91bba0SGirish Moodalbail * is opened.
13726e91bba0SGirish Moodalbail */
13736e91bba0SGirish Moodalbail /* ARGSUSED */
13746e91bba0SGirish Moodalbail extern boolean_t
ipmgmt_aobjmap_init(void * arg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)13756e91bba0SGirish Moodalbail ipmgmt_aobjmap_init(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
13766e91bba0SGirish Moodalbail int *errp)
13776e91bba0SGirish Moodalbail {
13786e91bba0SGirish Moodalbail nvpair_t *nvp = NULL;
13796e91bba0SGirish Moodalbail char *name, *strval = NULL;
1380ab618543SJohn Levon ipmgmt_aobjmap_t node;
13816e91bba0SGirish Moodalbail struct sockaddr_in6 *in6;
13826e91bba0SGirish Moodalbail
13836e91bba0SGirish Moodalbail *errp = 0;
13846e91bba0SGirish Moodalbail node.am_next = NULL;
13856e91bba0SGirish Moodalbail for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
13866e91bba0SGirish Moodalbail nvp = nvlist_next_nvpair(db_nvl, nvp)) {
13876e91bba0SGirish Moodalbail name = nvpair_name(nvp);
13886e91bba0SGirish Moodalbail
13896e91bba0SGirish Moodalbail if ((*errp = nvpair_value_string(nvp, &strval)) != 0)
13906e91bba0SGirish Moodalbail return (B_TRUE);
13916e91bba0SGirish Moodalbail if (strcmp(IPADM_NVP_AOBJNAME, name) == 0) {
13926e91bba0SGirish Moodalbail (void) strlcpy(node.am_aobjname, strval,
13936e91bba0SGirish Moodalbail sizeof (node.am_aobjname));
13946e91bba0SGirish Moodalbail } else if (strcmp(IPADM_NVP_IFNAME, name) == 0) {
13956e91bba0SGirish Moodalbail (void) strlcpy(node.am_ifname, strval,
13966e91bba0SGirish Moodalbail sizeof (node.am_ifname));
13976e91bba0SGirish Moodalbail } else if (strcmp(IPADM_NVP_LIFNUM, name) == 0) {
13986e91bba0SGirish Moodalbail node.am_lnum = atoi(strval);
13996e91bba0SGirish Moodalbail } else if (strcmp(IPADM_NVP_FAMILY, name) == 0) {
14006e91bba0SGirish Moodalbail node.am_family = (sa_family_t)atoi(strval);
14016e91bba0SGirish Moodalbail } else if (strcmp(FLAGS, name) == 0) {
14026e91bba0SGirish Moodalbail node.am_flags = atoi(strval);
14036e91bba0SGirish Moodalbail } else if (strcmp(ATYPE, name) == 0) {
14046e91bba0SGirish Moodalbail node.am_atype = (ipadm_addr_type_t)atoi(strval);
14056e91bba0SGirish Moodalbail } else if (strcmp(IPADM_NVP_IPNUMADDR, name) == 0) {
14066e91bba0SGirish Moodalbail if (node.am_atype == IPADM_ADDR_IPV6_ADDRCONF) {
1407b31320a7SChris Fraire in6 = &node.ipmgmt_am_ifid;
14086e91bba0SGirish Moodalbail if (strcmp(strval, "default") == 0) {
1409b31320a7SChris Fraire bzero(in6,
1410b31320a7SChris Fraire sizeof (node.ipmgmt_am_ifid));
1411b31320a7SChris Fraire node.ipmgmt_am_linklocal = B_TRUE;
14126e91bba0SGirish Moodalbail } else {
14136e91bba0SGirish Moodalbail (void) inet_pton(AF_INET6, strval,
14146e91bba0SGirish Moodalbail &in6->sin6_addr);
14156e91bba0SGirish Moodalbail if (IN6_IS_ADDR_UNSPECIFIED(
14166e91bba0SGirish Moodalbail &in6->sin6_addr))
1417b31320a7SChris Fraire node.ipmgmt_am_linklocal =
1418b31320a7SChris Fraire B_TRUE;
14196e91bba0SGirish Moodalbail }
14206e91bba0SGirish Moodalbail }
14216e91bba0SGirish Moodalbail }
14226e91bba0SGirish Moodalbail }
14236e91bba0SGirish Moodalbail
14246e91bba0SGirish Moodalbail /* we have all the information we need, add the node */
14256e91bba0SGirish Moodalbail *errp = i_ipmgmt_add_amnode(&node);
14266e91bba0SGirish Moodalbail
14276e91bba0SGirish Moodalbail return (B_TRUE);
14286e91bba0SGirish Moodalbail }
14296e91bba0SGirish Moodalbail
14306e91bba0SGirish Moodalbail /*
14316e91bba0SGirish Moodalbail * Updates an entry from the temporary cache file, which matches the given
14326e91bba0SGirish Moodalbail * address object name.
14336e91bba0SGirish Moodalbail */
14346e91bba0SGirish Moodalbail /* ARGSUSED */
14356e91bba0SGirish Moodalbail static boolean_t
ipmgmt_update_aobjmap(void * arg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)14366e91bba0SGirish Moodalbail ipmgmt_update_aobjmap(void *arg, nvlist_t *db_nvl, char *buf,
14376e91bba0SGirish Moodalbail size_t buflen, int *errp)
14386e91bba0SGirish Moodalbail {
14396e91bba0SGirish Moodalbail ipadm_dbwrite_cbarg_t *cb = arg;
14406e91bba0SGirish Moodalbail nvlist_t *in_nvl = cb->dbw_nvl;
14416e91bba0SGirish Moodalbail uint32_t flags = cb->dbw_flags;
14426e91bba0SGirish Moodalbail char *db_lifnumstr = NULL, *in_lifnumstr = NULL;
14436e91bba0SGirish Moodalbail
14446e91bba0SGirish Moodalbail *errp = 0;
14456e91bba0SGirish Moodalbail if (!ipmgmt_nvlist_intersects(db_nvl, in_nvl))
14466e91bba0SGirish Moodalbail return (B_TRUE);
14476e91bba0SGirish Moodalbail
14486e91bba0SGirish Moodalbail if (flags & IPMGMT_ATYPE_V6ACONF) {
14496e91bba0SGirish Moodalbail if (nvlist_lookup_string(db_nvl, IPADM_NVP_LIFNUM,
14506e91bba0SGirish Moodalbail &db_lifnumstr) != 0 ||
14516e91bba0SGirish Moodalbail nvlist_lookup_string(in_nvl, IPADM_NVP_LIFNUM,
14526e91bba0SGirish Moodalbail &in_lifnumstr) != 0 ||
14536e91bba0SGirish Moodalbail (atoi(db_lifnumstr) != -1 && atoi(in_lifnumstr) != -1 &&
14546e91bba0SGirish Moodalbail strcmp(db_lifnumstr, in_lifnumstr) != 0))
14556e91bba0SGirish Moodalbail return (B_TRUE);
14566e91bba0SGirish Moodalbail }
14576e91bba0SGirish Moodalbail
14586e91bba0SGirish Moodalbail /* we found the match */
14596e91bba0SGirish Moodalbail (void) memset(buf, 0, buflen);
14606e91bba0SGirish Moodalbail if (ipadm_nvlist2str(in_nvl, buf, buflen) == 0) {
14616e91bba0SGirish Moodalbail /* buffer overflow */
14626e91bba0SGirish Moodalbail *errp = ENOBUFS;
14636e91bba0SGirish Moodalbail }
14646e91bba0SGirish Moodalbail
14656e91bba0SGirish Moodalbail /* stop the walker */
14666e91bba0SGirish Moodalbail return (B_FALSE);
14676e91bba0SGirish Moodalbail }
14686e91bba0SGirish Moodalbail
14696e91bba0SGirish Moodalbail /*
14706e91bba0SGirish Moodalbail * Deletes an entry from the temporary cache file, which matches the given
14716e91bba0SGirish Moodalbail * address object name.
14726e91bba0SGirish Moodalbail */
14736e91bba0SGirish Moodalbail /* ARGSUSED */
14746e91bba0SGirish Moodalbail static boolean_t
ipmgmt_delete_aobjmap(void * arg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)14756e91bba0SGirish Moodalbail ipmgmt_delete_aobjmap(void *arg, nvlist_t *db_nvl, char *buf,
14766e91bba0SGirish Moodalbail size_t buflen, int *errp)
14776e91bba0SGirish Moodalbail {
14786e91bba0SGirish Moodalbail ipmgmt_aobjmap_t *nodep = arg;
14796e91bba0SGirish Moodalbail char *db_lifnumstr = NULL;
14806e91bba0SGirish Moodalbail
14816e91bba0SGirish Moodalbail *errp = 0;
14826e91bba0SGirish Moodalbail if (!ipmgmt_nvlist_match(db_nvl, NULL, nodep->am_ifname,
14836e91bba0SGirish Moodalbail nodep->am_aobjname))
14846e91bba0SGirish Moodalbail return (B_TRUE);
14856e91bba0SGirish Moodalbail
14866e91bba0SGirish Moodalbail if (nodep->am_atype == IPADM_ADDR_IPV6_ADDRCONF) {
14876e91bba0SGirish Moodalbail if (nvlist_lookup_string(db_nvl, IPADM_NVP_LIFNUM,
14886e91bba0SGirish Moodalbail &db_lifnumstr) != 0 || atoi(db_lifnumstr) != nodep->am_lnum)
14896e91bba0SGirish Moodalbail return (B_TRUE);
14906e91bba0SGirish Moodalbail }
14916e91bba0SGirish Moodalbail
14926e91bba0SGirish Moodalbail /* we found the match, delete the line from the db */
14936e91bba0SGirish Moodalbail buf[0] = '\0';
14946e91bba0SGirish Moodalbail
14956e91bba0SGirish Moodalbail /* stop the walker */
14966e91bba0SGirish Moodalbail return (B_FALSE);
14976e91bba0SGirish Moodalbail }
14986e91bba0SGirish Moodalbail
14996e91bba0SGirish Moodalbail /*
15006e91bba0SGirish Moodalbail * Adds or deletes aobjmap node information into a temporary cache file.
15016e91bba0SGirish Moodalbail */
15026e91bba0SGirish Moodalbail extern int
ipmgmt_persist_aobjmap(ipmgmt_aobjmap_t * nodep,ipadm_db_op_t op)15036e91bba0SGirish Moodalbail ipmgmt_persist_aobjmap(ipmgmt_aobjmap_t *nodep, ipadm_db_op_t op)
15046e91bba0SGirish Moodalbail {
15056e91bba0SGirish Moodalbail int err;
15066e91bba0SGirish Moodalbail ipadm_dbwrite_cbarg_t cb;
15076e91bba0SGirish Moodalbail nvlist_t *nvl = NULL;
15086e91bba0SGirish Moodalbail
15096e91bba0SGirish Moodalbail if (op == IPADM_DB_WRITE) {
15106e91bba0SGirish Moodalbail if ((err = i_ipmgmt_node2nvl(&nvl, nodep)) != 0)
15116e91bba0SGirish Moodalbail return (err);
15126e91bba0SGirish Moodalbail cb.dbw_nvl = nvl;
15136e91bba0SGirish Moodalbail if (nodep->am_atype == IPADM_ADDR_IPV6_ADDRCONF)
15146e91bba0SGirish Moodalbail cb.dbw_flags = IPMGMT_ATYPE_V6ACONF;
15156e91bba0SGirish Moodalbail else
15166e91bba0SGirish Moodalbail cb.dbw_flags = 0;
15176e91bba0SGirish Moodalbail
15186e91bba0SGirish Moodalbail err = ipadm_rw_db(ipmgmt_update_aobjmap, &cb,
15196e91bba0SGirish Moodalbail ADDROBJ_MAPPING_DB_FILE, IPADM_FILE_MODE, IPADM_DB_WRITE);
15206e91bba0SGirish Moodalbail nvlist_free(nvl);
15216e91bba0SGirish Moodalbail } else {
15226e91bba0SGirish Moodalbail assert(op == IPADM_DB_DELETE);
15236e91bba0SGirish Moodalbail
15246e91bba0SGirish Moodalbail err = ipadm_rw_db(ipmgmt_delete_aobjmap, nodep,
15256e91bba0SGirish Moodalbail ADDROBJ_MAPPING_DB_FILE, IPADM_FILE_MODE, IPADM_DB_DELETE);
15266e91bba0SGirish Moodalbail }
15276e91bba0SGirish Moodalbail return (err);
15286e91bba0SGirish Moodalbail }
1529550b6e40SSowmini Varadhan
15308887b57dSGirish Moodalbail /*
15318887b57dSGirish Moodalbail * upgrades the ipadm data-store. It renames all the old private protocol
15328887b57dSGirish Moodalbail * property names which start with leading protocol names to begin with
15338887b57dSGirish Moodalbail * IPADM_PRIV_PROP_PREFIX.
15348887b57dSGirish Moodalbail */
15358887b57dSGirish Moodalbail /* ARGSUSED */
15368887b57dSGirish Moodalbail boolean_t
ipmgmt_db_upgrade(void * arg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)15378887b57dSGirish Moodalbail ipmgmt_db_upgrade(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
15388887b57dSGirish Moodalbail int *errp)
15398887b57dSGirish Moodalbail {
15408887b57dSGirish Moodalbail nvpair_t *nvp;
15418887b57dSGirish Moodalbail char *name, *pname = NULL, *protostr = NULL, *pval = NULL;
15428887b57dSGirish Moodalbail uint_t proto, nproto;
15438887b57dSGirish Moodalbail char nname[IPMGMT_STRSIZE], tmpstr[IPMGMT_STRSIZE];
15448887b57dSGirish Moodalbail
15458887b57dSGirish Moodalbail *errp = 0;
15468887b57dSGirish Moodalbail /*
15478887b57dSGirish Moodalbail * We are interested in lines which contain protocol properties. We
15488887b57dSGirish Moodalbail * walk through other lines in the DB.
15498887b57dSGirish Moodalbail */
15508887b57dSGirish Moodalbail if (nvlist_exists(db_nvl, IPADM_NVP_IFNAME) ||
15518887b57dSGirish Moodalbail nvlist_exists(db_nvl, IPADM_NVP_AOBJNAME)) {
15528887b57dSGirish Moodalbail return (B_TRUE);
15538887b57dSGirish Moodalbail }
15548887b57dSGirish Moodalbail assert(nvlist_exists(db_nvl, IPADM_NVP_PROTONAME));
15558887b57dSGirish Moodalbail
15568887b57dSGirish Moodalbail /*
15578887b57dSGirish Moodalbail * extract the propname from the `db_nvl' and also extract the
15588887b57dSGirish Moodalbail * protocol from the `db_nvl'.
15598887b57dSGirish Moodalbail */
15608887b57dSGirish Moodalbail for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
15618887b57dSGirish Moodalbail nvp = nvlist_next_nvpair(db_nvl, nvp)) {
15628887b57dSGirish Moodalbail name = nvpair_name(nvp);
15638887b57dSGirish Moodalbail if (strcmp(name, IPADM_NVP_PROTONAME) == 0) {
15648887b57dSGirish Moodalbail if (nvpair_value_string(nvp, &protostr) != 0)
15658887b57dSGirish Moodalbail return (B_TRUE);
15668887b57dSGirish Moodalbail } else {
15678887b57dSGirish Moodalbail assert(!IPADM_PRIV_NVP(name));
15688887b57dSGirish Moodalbail pname = name;
15698887b57dSGirish Moodalbail if (nvpair_value_string(nvp, &pval) != 0)
15708887b57dSGirish Moodalbail return (B_TRUE);
15718887b57dSGirish Moodalbail }
15728887b57dSGirish Moodalbail }
15738887b57dSGirish Moodalbail
15748887b57dSGirish Moodalbail /* if the private property is in the right format return */
15758887b57dSGirish Moodalbail if (strncmp(pname, IPADM_PERSIST_PRIVPROP_PREFIX,
15768887b57dSGirish Moodalbail strlen(IPADM_PERSIST_PRIVPROP_PREFIX)) == 0) {
15778887b57dSGirish Moodalbail return (B_TRUE);
15788887b57dSGirish Moodalbail }
15798887b57dSGirish Moodalbail /* if it's a public property move onto the next property */
15808887b57dSGirish Moodalbail nproto = proto = ipadm_str2proto(protostr);
15818887b57dSGirish Moodalbail if (ipadm_legacy2new_propname(pname, nname, sizeof (nname),
15828887b57dSGirish Moodalbail &nproto) != 0) {
15838887b57dSGirish Moodalbail return (B_TRUE);
15848887b57dSGirish Moodalbail }
15858887b57dSGirish Moodalbail
15868887b57dSGirish Moodalbail /* replace the old protocol with new protocol, if required */
15878887b57dSGirish Moodalbail if (nproto != proto) {
15888887b57dSGirish Moodalbail protostr = ipadm_proto2str(nproto);
15898887b57dSGirish Moodalbail if (nvlist_add_string(db_nvl, IPADM_NVP_PROTONAME,
15908887b57dSGirish Moodalbail protostr) != 0) {
15918887b57dSGirish Moodalbail return (B_TRUE);
15928887b57dSGirish Moodalbail }
15938887b57dSGirish Moodalbail }
15948887b57dSGirish Moodalbail
15958887b57dSGirish Moodalbail /* replace the old property name with new property name, if required */
15968887b57dSGirish Moodalbail /* add the prefix to property name */
15978887b57dSGirish Moodalbail (void) snprintf(tmpstr, sizeof (tmpstr), "_%s", nname);
15988887b57dSGirish Moodalbail if (nvlist_add_string(db_nvl, tmpstr, pval) != 0 ||
15998887b57dSGirish Moodalbail nvlist_remove(db_nvl, pname, DATA_TYPE_STRING) != 0) {
16008887b57dSGirish Moodalbail return (B_TRUE);
16018887b57dSGirish Moodalbail }
16028887b57dSGirish Moodalbail (void) memset(buf, 0, buflen);
16038887b57dSGirish Moodalbail if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
16048887b57dSGirish Moodalbail /* buffer overflow */
16058887b57dSGirish Moodalbail *errp = ENOBUFS;
16068887b57dSGirish Moodalbail }
16078887b57dSGirish Moodalbail return (B_TRUE);
16088887b57dSGirish Moodalbail }
1609550b6e40SSowmini Varadhan
1610550b6e40SSowmini Varadhan /*
16118887b57dSGirish Moodalbail * Called during boot.
16128887b57dSGirish Moodalbail *
16138887b57dSGirish Moodalbail * Walk through the DB and apply all the global module properties. We plow
16148887b57dSGirish Moodalbail * through the DB even if we fail to apply property.
1615550b6e40SSowmini Varadhan */
16168887b57dSGirish Moodalbail /* ARGSUSED */
16178887b57dSGirish Moodalbail static boolean_t
ipmgmt_db_init(void * cbarg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)16188887b57dSGirish Moodalbail ipmgmt_db_init(void *cbarg, nvlist_t *db_nvl, char *buf, size_t buflen,
16198887b57dSGirish Moodalbail int *errp)
16208887b57dSGirish Moodalbail {
16218887b57dSGirish Moodalbail ipadm_handle_t iph = cbarg;
1622a73be61aSHans Rosenfeld nvpair_t *nvp, *pnvp = NULL;
16238887b57dSGirish Moodalbail char *strval = NULL, *name, *mod = NULL, *pname;
16248887b57dSGirish Moodalbail char tmpstr[IPMGMT_STRSIZE];
16258887b57dSGirish Moodalbail uint_t proto;
16268887b57dSGirish Moodalbail
16278887b57dSGirish Moodalbail /*
16288887b57dSGirish Moodalbail * We could have used nvl_exists() directly, however we need several
16298887b57dSGirish Moodalbail * calls to it and each call traverses the list. Since this codepath
16308887b57dSGirish Moodalbail * is exercised during boot, let's traverse the list ourselves and do
16318887b57dSGirish Moodalbail * the necessary checks.
16328887b57dSGirish Moodalbail */
16338887b57dSGirish Moodalbail for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
16348887b57dSGirish Moodalbail nvp = nvlist_next_nvpair(db_nvl, nvp)) {
16358887b57dSGirish Moodalbail name = nvpair_name(nvp);
16368887b57dSGirish Moodalbail if (IPADM_PRIV_NVP(name)) {
16378887b57dSGirish Moodalbail if (strcmp(name, IPADM_NVP_IFNAME) == 0 ||
16388887b57dSGirish Moodalbail strcmp(name, IPADM_NVP_AOBJNAME) == 0)
16398887b57dSGirish Moodalbail return (B_TRUE);
16408887b57dSGirish Moodalbail else if (strcmp(name, IPADM_NVP_PROTONAME) == 0 &&
16418887b57dSGirish Moodalbail nvpair_value_string(nvp, &mod) != 0)
16428887b57dSGirish Moodalbail return (B_TRUE);
16438887b57dSGirish Moodalbail } else {
16448887b57dSGirish Moodalbail /* possible a property */
16458887b57dSGirish Moodalbail pnvp = nvp;
16468887b57dSGirish Moodalbail }
16478887b57dSGirish Moodalbail }
16488887b57dSGirish Moodalbail
1649a73be61aSHans Rosenfeld /* If we are here then we have found a global property */
16508887b57dSGirish Moodalbail assert(mod != NULL);
16518887b57dSGirish Moodalbail assert(nvpair_type(pnvp) == DATA_TYPE_STRING);
16528887b57dSGirish Moodalbail
16538887b57dSGirish Moodalbail proto = ipadm_str2proto(mod);
16548887b57dSGirish Moodalbail name = nvpair_name(pnvp);
16558887b57dSGirish Moodalbail if (nvpair_value_string(pnvp, &strval) == 0) {
16568887b57dSGirish Moodalbail if (strncmp(name, IPADM_PERSIST_PRIVPROP_PREFIX,
16578887b57dSGirish Moodalbail strlen(IPADM_PERSIST_PRIVPROP_PREFIX)) == 0) {
16588887b57dSGirish Moodalbail /* private protocol property */
16598887b57dSGirish Moodalbail pname = &name[1];
16608887b57dSGirish Moodalbail } else if (ipadm_legacy2new_propname(name, tmpstr,
16618887b57dSGirish Moodalbail sizeof (tmpstr), &proto) == 0) {
16628887b57dSGirish Moodalbail pname = tmpstr;
16638887b57dSGirish Moodalbail } else {
16648887b57dSGirish Moodalbail pname = name;
16658887b57dSGirish Moodalbail }
16668887b57dSGirish Moodalbail if (ipadm_set_prop(iph, pname, strval, proto,
16678887b57dSGirish Moodalbail IPADM_OPT_ACTIVE) != IPADM_SUCCESS) {
16688887b57dSGirish Moodalbail ipmgmt_log(LOG_WARNING, "Failed to reapply property %s",
16698887b57dSGirish Moodalbail pname);
16708887b57dSGirish Moodalbail }
16718887b57dSGirish Moodalbail }
16728887b57dSGirish Moodalbail
16738887b57dSGirish Moodalbail return (B_TRUE);
16748887b57dSGirish Moodalbail }
16758887b57dSGirish Moodalbail
16768887b57dSGirish Moodalbail /* initialize global module properties */
16778887b57dSGirish Moodalbail void
ipmgmt_init_prop()16788887b57dSGirish Moodalbail ipmgmt_init_prop()
16798887b57dSGirish Moodalbail {
16808887b57dSGirish Moodalbail ipadm_handle_t iph = NULL;
16818887b57dSGirish Moodalbail
16828887b57dSGirish Moodalbail if (ipadm_open(&iph, IPH_INIT) != IPADM_SUCCESS) {
16838887b57dSGirish Moodalbail ipmgmt_log(LOG_WARNING, "Could not reapply any of the "
16848887b57dSGirish Moodalbail "persisted protocol properties");
16858887b57dSGirish Moodalbail return;
16868887b57dSGirish Moodalbail }
16878887b57dSGirish Moodalbail /* ipmgmt_db_init() logs warnings if there are any issues */
16888887b57dSGirish Moodalbail (void) ipmgmt_db_walk(ipmgmt_db_init, iph, IPADM_DB_READ);
16898887b57dSGirish Moodalbail ipadm_close(iph);
16908887b57dSGirish Moodalbail }
16918887b57dSGirish Moodalbail
16928887b57dSGirish Moodalbail void
ipmgmt_release_scf_resources(scf_resources_t * res)1693550b6e40SSowmini Varadhan ipmgmt_release_scf_resources(scf_resources_t *res)
1694550b6e40SSowmini Varadhan {
1695550b6e40SSowmini Varadhan scf_entry_destroy(res->sr_ent);
1696550b6e40SSowmini Varadhan scf_transaction_destroy(res->sr_tx);
1697550b6e40SSowmini Varadhan scf_value_destroy(res->sr_val);
1698550b6e40SSowmini Varadhan scf_property_destroy(res->sr_prop);
1699550b6e40SSowmini Varadhan scf_pg_destroy(res->sr_pg);
1700550b6e40SSowmini Varadhan scf_instance_destroy(res->sr_inst);
1701550b6e40SSowmini Varadhan (void) scf_handle_unbind(res->sr_handle);
1702550b6e40SSowmini Varadhan scf_handle_destroy(res->sr_handle);
1703550b6e40SSowmini Varadhan }
1704550b6e40SSowmini Varadhan
1705550b6e40SSowmini Varadhan /*
17068887b57dSGirish Moodalbail * It creates the necessary SCF handles and binds the given `fmri' to an
17078887b57dSGirish Moodalbail * instance. These resources are required for retrieving property value,
17088887b57dSGirish Moodalbail * creating property groups and modifying property values.
1709550b6e40SSowmini Varadhan */
17108887b57dSGirish Moodalbail int
ipmgmt_create_scf_resources(const char * fmri,scf_resources_t * res)1711550b6e40SSowmini Varadhan ipmgmt_create_scf_resources(const char *fmri, scf_resources_t *res)
1712550b6e40SSowmini Varadhan {
1713550b6e40SSowmini Varadhan res->sr_tx = NULL;
1714550b6e40SSowmini Varadhan res->sr_ent = NULL;
1715550b6e40SSowmini Varadhan res->sr_inst = NULL;
1716550b6e40SSowmini Varadhan res->sr_pg = NULL;
1717550b6e40SSowmini Varadhan res->sr_prop = NULL;
1718550b6e40SSowmini Varadhan res->sr_val = NULL;
1719550b6e40SSowmini Varadhan
17208887b57dSGirish Moodalbail if ((res->sr_handle = scf_handle_create(SCF_VERSION)) == NULL)
1721550b6e40SSowmini Varadhan return (-1);
1722550b6e40SSowmini Varadhan
1723550b6e40SSowmini Varadhan if (scf_handle_bind(res->sr_handle) != 0) {
1724550b6e40SSowmini Varadhan scf_handle_destroy(res->sr_handle);
1725550b6e40SSowmini Varadhan return (-1);
1726550b6e40SSowmini Varadhan }
17278887b57dSGirish Moodalbail if ((res->sr_inst = scf_instance_create(res->sr_handle)) == NULL)
1728550b6e40SSowmini Varadhan goto failure;
1729550b6e40SSowmini Varadhan if (scf_handle_decode_fmri(res->sr_handle, fmri, NULL, NULL,
1730550b6e40SSowmini Varadhan res->sr_inst, NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
1731550b6e40SSowmini Varadhan goto failure;
1732550b6e40SSowmini Varadhan }
17338887b57dSGirish Moodalbail /* we will create the rest of the resources on demand */
1734550b6e40SSowmini Varadhan return (0);
1735550b6e40SSowmini Varadhan
1736550b6e40SSowmini Varadhan failure:
17378887b57dSGirish Moodalbail ipmgmt_log(LOG_WARNING, "failed to create scf resources: %s",
17388887b57dSGirish Moodalbail scf_strerror(scf_error()));
1739550b6e40SSowmini Varadhan ipmgmt_release_scf_resources(res);
1740550b6e40SSowmini Varadhan return (-1);
1741550b6e40SSowmini Varadhan }
1742550b6e40SSowmini Varadhan
17438887b57dSGirish Moodalbail /*
17448887b57dSGirish Moodalbail * persists the `pval' for a given property `pname' in SCF. The only supported
17458887b57dSGirish Moodalbail * SCF property types are INTEGER and ASTRING.
17468887b57dSGirish Moodalbail */
1747550b6e40SSowmini Varadhan static int
ipmgmt_set_scfprop_value(scf_resources_t * res,const char * pname,void * pval,scf_type_t ptype)17488887b57dSGirish Moodalbail ipmgmt_set_scfprop_value(scf_resources_t *res, const char *pname, void *pval,
17498887b57dSGirish Moodalbail scf_type_t ptype)
1750550b6e40SSowmini Varadhan {
1751550b6e40SSowmini Varadhan int result = -1;
1752550b6e40SSowmini Varadhan boolean_t new;
1753550b6e40SSowmini Varadhan
17548887b57dSGirish Moodalbail if ((res->sr_val = scf_value_create(res->sr_handle)) == NULL)
17558887b57dSGirish Moodalbail goto failure;
17568887b57dSGirish Moodalbail switch (ptype) {
17578887b57dSGirish Moodalbail case SCF_TYPE_INTEGER:
17588887b57dSGirish Moodalbail scf_value_set_integer(res->sr_val, *(int64_t *)pval);
17598887b57dSGirish Moodalbail break;
17608887b57dSGirish Moodalbail case SCF_TYPE_ASTRING:
17618887b57dSGirish Moodalbail if (scf_value_set_astring(res->sr_val, (char *)pval) != 0) {
17628887b57dSGirish Moodalbail ipmgmt_log(LOG_WARNING, "Error setting string value %s "
17638887b57dSGirish Moodalbail "for property %s: %s", pval, pname,
17648887b57dSGirish Moodalbail scf_strerror(scf_error()));
17658887b57dSGirish Moodalbail goto failure;
17668887b57dSGirish Moodalbail }
17678887b57dSGirish Moodalbail break;
17688887b57dSGirish Moodalbail default:
1769550b6e40SSowmini Varadhan goto failure;
1770550b6e40SSowmini Varadhan }
17718887b57dSGirish Moodalbail
17728887b57dSGirish Moodalbail if ((res->sr_tx = scf_transaction_create(res->sr_handle)) == NULL)
17738887b57dSGirish Moodalbail goto failure;
17748887b57dSGirish Moodalbail if ((res->sr_ent = scf_entry_create(res->sr_handle)) == NULL)
17758887b57dSGirish Moodalbail goto failure;
17768887b57dSGirish Moodalbail if ((res->sr_prop = scf_property_create(res->sr_handle)) == NULL)
17778887b57dSGirish Moodalbail goto failure;
17788887b57dSGirish Moodalbail
17798887b57dSGirish Moodalbail retry:
17808887b57dSGirish Moodalbail new = (scf_pg_get_property(res->sr_pg, pname, res->sr_prop) != 0);
17818887b57dSGirish Moodalbail if (scf_transaction_start(res->sr_tx, res->sr_pg) == -1)
17828887b57dSGirish Moodalbail goto failure;
1783550b6e40SSowmini Varadhan if (new) {
1784550b6e40SSowmini Varadhan if (scf_transaction_property_new(res->sr_tx, res->sr_ent,
17858887b57dSGirish Moodalbail pname, ptype) == -1) {
1786550b6e40SSowmini Varadhan goto failure;
1787550b6e40SSowmini Varadhan }
1788550b6e40SSowmini Varadhan } else {
1789550b6e40SSowmini Varadhan if (scf_transaction_property_change(res->sr_tx, res->sr_ent,
17908887b57dSGirish Moodalbail pname, ptype) == -1) {
1791550b6e40SSowmini Varadhan goto failure;
1792550b6e40SSowmini Varadhan }
1793550b6e40SSowmini Varadhan }
1794550b6e40SSowmini Varadhan
17958887b57dSGirish Moodalbail if (scf_entry_add_value(res->sr_ent, res->sr_val) != 0)
1796550b6e40SSowmini Varadhan goto failure;
1797550b6e40SSowmini Varadhan
1798550b6e40SSowmini Varadhan result = scf_transaction_commit(res->sr_tx);
1799550b6e40SSowmini Varadhan if (result == 0) {
1800550b6e40SSowmini Varadhan scf_transaction_reset(res->sr_tx);
1801550b6e40SSowmini Varadhan if (scf_pg_update(res->sr_pg) == -1) {
1802550b6e40SSowmini Varadhan goto failure;
1803550b6e40SSowmini Varadhan }
1804550b6e40SSowmini Varadhan goto retry;
1805550b6e40SSowmini Varadhan }
1806550b6e40SSowmini Varadhan if (result == -1)
1807550b6e40SSowmini Varadhan goto failure;
1808550b6e40SSowmini Varadhan return (0);
1809550b6e40SSowmini Varadhan
1810550b6e40SSowmini Varadhan failure:
18118887b57dSGirish Moodalbail ipmgmt_log(LOG_WARNING, "failed to save the data in SCF: %s",
18128887b57dSGirish Moodalbail scf_strerror(scf_error()));
1813550b6e40SSowmini Varadhan return (-1);
1814550b6e40SSowmini Varadhan }
1815550b6e40SSowmini Varadhan
1816550b6e40SSowmini Varadhan /*
18178887b57dSGirish Moodalbail * Given a `pgname'/`pname', it retrieves the value based on `ptype' and
18188887b57dSGirish Moodalbail * places it in `pval'.
1819550b6e40SSowmini Varadhan */
18208887b57dSGirish Moodalbail static int
ipmgmt_get_scfprop(scf_resources_t * res,const char * pgname,const char * pname,void * pval,scf_type_t ptype)18218887b57dSGirish Moodalbail ipmgmt_get_scfprop(scf_resources_t *res, const char *pgname, const char *pname,
18228887b57dSGirish Moodalbail void *pval, scf_type_t ptype)
1823550b6e40SSowmini Varadhan {
18248887b57dSGirish Moodalbail ssize_t numvals;
1825550b6e40SSowmini Varadhan scf_simple_prop_t *prop;
1826550b6e40SSowmini Varadhan
18278887b57dSGirish Moodalbail prop = scf_simple_prop_get(res->sr_handle, IPMGMTD_FMRI, pgname, pname);
1828550b6e40SSowmini Varadhan numvals = scf_simple_prop_numvalues(prop);
18298887b57dSGirish Moodalbail if (numvals <= 0)
18308887b57dSGirish Moodalbail goto ret;
18318887b57dSGirish Moodalbail switch (ptype) {
18328887b57dSGirish Moodalbail case SCF_TYPE_INTEGER:
18338887b57dSGirish Moodalbail *(int64_t **)pval = scf_simple_prop_next_integer(prop);
18348887b57dSGirish Moodalbail break;
18358887b57dSGirish Moodalbail case SCF_TYPE_ASTRING:
18368887b57dSGirish Moodalbail *(char **)pval = scf_simple_prop_next_astring(prop);
18378887b57dSGirish Moodalbail break;
1838a73be61aSHans Rosenfeld default:
1839a73be61aSHans Rosenfeld break;
1840550b6e40SSowmini Varadhan }
18418887b57dSGirish Moodalbail ret:
18428887b57dSGirish Moodalbail scf_simple_prop_free(prop);
18438887b57dSGirish Moodalbail return (numvals);
18448887b57dSGirish Moodalbail }
1845550b6e40SSowmini Varadhan
18468887b57dSGirish Moodalbail /*
18478887b57dSGirish Moodalbail * It stores the `pval' for given `pgname'/`pname' property group in SCF.
18488887b57dSGirish Moodalbail */
18498887b57dSGirish Moodalbail static int
ipmgmt_set_scfprop(scf_resources_t * res,const char * pgname,const char * pname,void * pval,scf_type_t ptype)18508887b57dSGirish Moodalbail ipmgmt_set_scfprop(scf_resources_t *res, const char *pgname, const char *pname,
18518887b57dSGirish Moodalbail void *pval, scf_type_t ptype)
18528887b57dSGirish Moodalbail {
18538887b57dSGirish Moodalbail scf_error_t err;
18548887b57dSGirish Moodalbail
18558887b57dSGirish Moodalbail if ((res->sr_pg = scf_pg_create(res->sr_handle)) == NULL) {
18568887b57dSGirish Moodalbail ipmgmt_log(LOG_WARNING, "failed to create property group: %s",
18578887b57dSGirish Moodalbail scf_strerror(scf_error()));
18588887b57dSGirish Moodalbail return (-1);
18598887b57dSGirish Moodalbail }
18608887b57dSGirish Moodalbail
18618887b57dSGirish Moodalbail if (scf_instance_add_pg(res->sr_inst, pgname, SCF_GROUP_APPLICATION,
18628887b57dSGirish Moodalbail 0, res->sr_pg) != 0) {
18638887b57dSGirish Moodalbail if ((err = scf_error()) != SCF_ERROR_EXISTS) {
18648887b57dSGirish Moodalbail ipmgmt_log(LOG_WARNING,
18658887b57dSGirish Moodalbail "Error adding property group '%s/%s': %s",
18668887b57dSGirish Moodalbail pgname, pname, scf_strerror(err));
18678887b57dSGirish Moodalbail return (-1);
18688887b57dSGirish Moodalbail }
1869550b6e40SSowmini Varadhan /*
18708887b57dSGirish Moodalbail * if the property group already exists, then we get the
18718887b57dSGirish Moodalbail * composed view of the property group for the given instance.
1872550b6e40SSowmini Varadhan */
18738887b57dSGirish Moodalbail if (scf_instance_get_pg_composed(res->sr_inst, NULL, pgname,
18748887b57dSGirish Moodalbail res->sr_pg) != 0) {
18758887b57dSGirish Moodalbail ipmgmt_log(LOG_WARNING, "Error getting composed view "
18768887b57dSGirish Moodalbail "of the property group '%s/%s': %s", pgname, pname,
18778887b57dSGirish Moodalbail scf_strerror(scf_error()));
18788887b57dSGirish Moodalbail return (-1);
1879550b6e40SSowmini Varadhan }
1880550b6e40SSowmini Varadhan }
1881550b6e40SSowmini Varadhan
18828887b57dSGirish Moodalbail return (ipmgmt_set_scfprop_value(res, pname, pval, ptype));
18838887b57dSGirish Moodalbail }
18848887b57dSGirish Moodalbail
18858887b57dSGirish Moodalbail /*
18868887b57dSGirish Moodalbail * Returns B_TRUE, if the non-global zone is being booted for the first time
18878887b57dSGirish Moodalbail * after being installed. This is required to setup the ipadm data-store for
18888887b57dSGirish Moodalbail * the first boot of the non-global zone. Please see, PSARC 2010/166,
18898887b57dSGirish Moodalbail * for more info.
18908887b57dSGirish Moodalbail *
18918887b57dSGirish Moodalbail * Note that, this API cannot be used to determine first boot post image-update.
18928887b57dSGirish Moodalbail * 'pkg image-update' clones the current BE and the existing value of
18938887b57dSGirish Moodalbail * ipmgmtd/first_boot_done will be carried forward and obviously it will be set
18948887b57dSGirish Moodalbail * to B_TRUE.
18958887b57dSGirish Moodalbail */
18968887b57dSGirish Moodalbail boolean_t
ipmgmt_ngz_firstboot_postinstall()18978887b57dSGirish Moodalbail ipmgmt_ngz_firstboot_postinstall()
18988887b57dSGirish Moodalbail {
18998887b57dSGirish Moodalbail scf_resources_t res;
19008887b57dSGirish Moodalbail boolean_t bval = B_TRUE;
19018887b57dSGirish Moodalbail char *strval;
19028887b57dSGirish Moodalbail
19038887b57dSGirish Moodalbail /* we always err on the side of caution */
19048887b57dSGirish Moodalbail if (ipmgmt_create_scf_resources(IPMGMTD_FMRI, &res) != 0)
19058887b57dSGirish Moodalbail return (bval);
19068887b57dSGirish Moodalbail
19078887b57dSGirish Moodalbail if (ipmgmt_get_scfprop(&res, IPMGMTD_APP_PG, IPMGMTD_PROP_FBD, &strval,
19088887b57dSGirish Moodalbail SCF_TYPE_ASTRING) > 0) {
19098887b57dSGirish Moodalbail bval = (strcmp(strval, IPMGMTD_TRUESTR) == 0 ?
19108887b57dSGirish Moodalbail B_FALSE : B_TRUE);
19118887b57dSGirish Moodalbail } else {
19128887b57dSGirish Moodalbail /*
19138887b57dSGirish Moodalbail * IPMGMTD_PROP_FBD does not exist in the SCF. Lets create it.
19148887b57dSGirish Moodalbail * Since we err on the side of caution, we ignore the return
19158887b57dSGirish Moodalbail * error and return B_TRUE.
19168887b57dSGirish Moodalbail */
19178887b57dSGirish Moodalbail (void) ipmgmt_set_scfprop(&res, IPMGMTD_APP_PG,
19188887b57dSGirish Moodalbail IPMGMTD_PROP_FBD, IPMGMTD_TRUESTR, SCF_TYPE_ASTRING);
1919550b6e40SSowmini Varadhan }
19208887b57dSGirish Moodalbail ipmgmt_release_scf_resources(&res);
19218887b57dSGirish Moodalbail return (bval);
19228887b57dSGirish Moodalbail }
19238887b57dSGirish Moodalbail
19248887b57dSGirish Moodalbail /*
19258887b57dSGirish Moodalbail * Returns B_TRUE, if the data-store needs upgrade otherwise returns B_FALSE.
19268887b57dSGirish Moodalbail * Today we have to take care of, one case of, upgrading from version 0 to
19278887b57dSGirish Moodalbail * version 1, so we will use boolean_t as means to decide if upgrade is needed
19288887b57dSGirish Moodalbail * or not. Further, the upcoming projects might completely move the flatfile
19298887b57dSGirish Moodalbail * data-store into SCF and hence we shall keep this interface simple.
19308887b57dSGirish Moodalbail */
19318887b57dSGirish Moodalbail boolean_t
ipmgmt_needs_upgrade(scf_resources_t * res)19328887b57dSGirish Moodalbail ipmgmt_needs_upgrade(scf_resources_t *res)
19338887b57dSGirish Moodalbail {
19348887b57dSGirish Moodalbail boolean_t bval = B_TRUE;
19358887b57dSGirish Moodalbail int64_t *verp;
1936550b6e40SSowmini Varadhan
19378887b57dSGirish Moodalbail if (ipmgmt_get_scfprop(res, IPMGMTD_APP_PG, IPMGMTD_PROP_DBVER,
19388887b57dSGirish Moodalbail &verp, SCF_TYPE_INTEGER) > 0) {
19398887b57dSGirish Moodalbail if (*verp == IPADM_DB_VERSION)
19408887b57dSGirish Moodalbail bval = B_FALSE;
1941550b6e40SSowmini Varadhan }
19428887b57dSGirish Moodalbail /*
19438887b57dSGirish Moodalbail * 'datastore_version' doesn't exist. Which means that we need to
19448887b57dSGirish Moodalbail * upgrade the datastore. We will create 'datastore_version' and set
19458887b57dSGirish Moodalbail * the version value to IPADM_DB_VERSION, after we upgrade the file.
19468887b57dSGirish Moodalbail */
19478887b57dSGirish Moodalbail return (bval);
19488887b57dSGirish Moodalbail }
1949550b6e40SSowmini Varadhan
19508887b57dSGirish Moodalbail /*
19518887b57dSGirish Moodalbail * This is called after the successful upgrade of the local data-store. With
19528887b57dSGirish Moodalbail * the data-store upgraded to recent version we don't have to do anything on
19538887b57dSGirish Moodalbail * subsequent reboots.
19548887b57dSGirish Moodalbail */
19558887b57dSGirish Moodalbail void
ipmgmt_update_dbver(scf_resources_t * res)19568887b57dSGirish Moodalbail ipmgmt_update_dbver(scf_resources_t *res)
19578887b57dSGirish Moodalbail {
19588887b57dSGirish Moodalbail int64_t version = IPADM_DB_VERSION;
19598887b57dSGirish Moodalbail
19608887b57dSGirish Moodalbail (void) ipmgmt_set_scfprop(res, IPMGMTD_APP_PG,
19618887b57dSGirish Moodalbail IPMGMTD_PROP_DBVER, &version, SCF_TYPE_INTEGER);
1962550b6e40SSowmini Varadhan }
1963a73be61aSHans Rosenfeld
1964a73be61aSHans Rosenfeld /*
1965a73be61aSHans Rosenfeld * Return TRUE if `ifname' has persistent configuration for the `af' address
1966a73be61aSHans Rosenfeld * family in the datastore.
1967a73be61aSHans Rosenfeld * It is possible to call the function with af == AF_UNSPEC, so in this case
1968a73be61aSHans Rosenfeld * the function returns TRUE if either AF_INET or AF_INET6 interface exists
1969a73be61aSHans Rosenfeld */
1970a73be61aSHans Rosenfeld boolean_t
ipmgmt_persist_if_exists(const char * ifname,sa_family_t af)1971a73be61aSHans Rosenfeld ipmgmt_persist_if_exists(const char *ifname, sa_family_t af)
1972a73be61aSHans Rosenfeld {
1973a73be61aSHans Rosenfeld boolean_t exists = B_FALSE;
1974a73be61aSHans Rosenfeld nvlist_t *if_info_nvl;
1975a73be61aSHans Rosenfeld uint16_t *families = NULL;
1976a73be61aSHans Rosenfeld sa_family_t af_db;
1977a73be61aSHans Rosenfeld uint_t nelem = 0;
1978a73be61aSHans Rosenfeld
1979a73be61aSHans Rosenfeld if (ipmgmt_get_ifinfo_nvl(ifname, &if_info_nvl) != 0)
1980a73be61aSHans Rosenfeld goto done;
1981a73be61aSHans Rosenfeld
1982a73be61aSHans Rosenfeld if (nvlist_lookup_uint16_array(if_info_nvl, IPADM_NVP_FAMILIES,
1983a73be61aSHans Rosenfeld &families, &nelem) != 0)
1984a73be61aSHans Rosenfeld goto done;
1985a73be61aSHans Rosenfeld
1986a73be61aSHans Rosenfeld while (nelem-- > 0) {
1987a73be61aSHans Rosenfeld af_db = families[nelem];
1988a73be61aSHans Rosenfeld if (af_db == af || (af == AF_UNSPEC &&
1989a73be61aSHans Rosenfeld (af_db == AF_INET || af_db == AF_INET6))) {
1990a73be61aSHans Rosenfeld exists = B_TRUE;
1991a73be61aSHans Rosenfeld break;
1992a73be61aSHans Rosenfeld }
1993a73be61aSHans Rosenfeld }
1994a73be61aSHans Rosenfeld
1995a73be61aSHans Rosenfeld done:
1996a73be61aSHans Rosenfeld if (if_info_nvl != NULL)
1997a73be61aSHans Rosenfeld nvlist_free(if_info_nvl);
1998a73be61aSHans Rosenfeld
1999a73be61aSHans Rosenfeld return (exists);
2000a73be61aSHans Rosenfeld }
2001a73be61aSHans Rosenfeld
2002a73be61aSHans Rosenfeld /*
2003a73be61aSHans Rosenfeld * Retrieves the membership information for the requested mif_name
2004a73be61aSHans Rosenfeld * if mif_name is a member of a IPMP group, then gif_name will contain
2005a73be61aSHans Rosenfeld * the name of IPMP group interface, otherwise the variable will be empty
2006a73be61aSHans Rosenfeld */
2007a73be61aSHans Rosenfeld void
ipmgmt_get_group_interface(const char * mif_name,char * gif_name,size_t size)2008a73be61aSHans Rosenfeld ipmgmt_get_group_interface(const char *mif_name, char *gif_name, size_t size)
2009a73be61aSHans Rosenfeld {
2010a73be61aSHans Rosenfeld char *gif_name_from_nvl;
2011a73be61aSHans Rosenfeld nvlist_t *if_info_nvl;
2012a73be61aSHans Rosenfeld
2013a73be61aSHans Rosenfeld gif_name[0] = '\0';
2014a73be61aSHans Rosenfeld
2015a73be61aSHans Rosenfeld if (ipmgmt_get_ifinfo_nvl(mif_name, &if_info_nvl) != 0)
2016a73be61aSHans Rosenfeld goto done;
2017a73be61aSHans Rosenfeld
2018a73be61aSHans Rosenfeld if (nvlist_lookup_string(if_info_nvl, IPADM_NVP_GIFNAME,
2019a73be61aSHans Rosenfeld &gif_name_from_nvl) != 0)
2020a73be61aSHans Rosenfeld goto done;
2021a73be61aSHans Rosenfeld
2022a73be61aSHans Rosenfeld (void) strlcpy(gif_name, gif_name_from_nvl, size);
2023a73be61aSHans Rosenfeld
2024a73be61aSHans Rosenfeld done:
2025a73be61aSHans Rosenfeld if (if_info_nvl != NULL)
2026a73be61aSHans Rosenfeld nvlist_free(if_info_nvl);
2027a73be61aSHans Rosenfeld }
2028a73be61aSHans Rosenfeld
2029a73be61aSHans Rosenfeld static int
ipmgmt_get_ifinfo_nvl(const char * ifname,nvlist_t ** if_info_nvl)2030a73be61aSHans Rosenfeld ipmgmt_get_ifinfo_nvl(const char *ifname, nvlist_t **if_info_nvl)
2031a73be61aSHans Rosenfeld {
2032a73be61aSHans Rosenfeld ipmgmt_get_cbarg_t cbarg;
2033a73be61aSHans Rosenfeld nvpair_t *nvp;
2034a73be61aSHans Rosenfeld nvlist_t *nvl;
2035a73be61aSHans Rosenfeld int err;
2036a73be61aSHans Rosenfeld
2037a73be61aSHans Rosenfeld cbarg.cb_ifname = NULL;
2038a73be61aSHans Rosenfeld cbarg.cb_aobjname = NULL;
2039a73be61aSHans Rosenfeld cbarg.cb_ocnt = 0;
2040a73be61aSHans Rosenfeld
204147c607a3SAndy Fiddaman *if_info_nvl = NULL;
204247c607a3SAndy Fiddaman
2043a73be61aSHans Rosenfeld if ((err = nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0)) != 0)
2044a73be61aSHans Rosenfeld goto done;
2045a73be61aSHans Rosenfeld
2046a73be61aSHans Rosenfeld err = ipmgmt_db_walk(ipmgmt_db_getif, &cbarg, IPADM_DB_READ);
2047a73be61aSHans Rosenfeld if (err == ENOENT && cbarg.cb_ocnt > 0)
2048a73be61aSHans Rosenfeld err = 0;
2049a73be61aSHans Rosenfeld
2050a73be61aSHans Rosenfeld if (err != 0)
2051a73be61aSHans Rosenfeld goto done;
2052a73be61aSHans Rosenfeld
2053a73be61aSHans Rosenfeld for (nvp = nvlist_next_nvpair(cbarg.cb_onvl, NULL); nvp != NULL;
2054a73be61aSHans Rosenfeld nvp = nvlist_next_nvpair(cbarg.cb_onvl, nvp)) {
2055a73be61aSHans Rosenfeld
2056a73be61aSHans Rosenfeld if (strcmp(nvpair_name(nvp), ifname) != 0)
2057a73be61aSHans Rosenfeld continue;
2058a73be61aSHans Rosenfeld
2059a73be61aSHans Rosenfeld if ((err = nvpair_value_nvlist(nvp, &nvl)) != 0 ||
2060a73be61aSHans Rosenfeld (err = nvlist_dup(nvl, if_info_nvl, NV_UNIQUE_NAME)) != 0)
2061a73be61aSHans Rosenfeld *if_info_nvl = NULL;
2062a73be61aSHans Rosenfeld
2063a73be61aSHans Rosenfeld break;
2064a73be61aSHans Rosenfeld }
2065a73be61aSHans Rosenfeld
2066a73be61aSHans Rosenfeld done:
2067a73be61aSHans Rosenfeld nvlist_free(cbarg.cb_onvl);
2068a73be61aSHans Rosenfeld
2069a73be61aSHans Rosenfeld return (err);
2070a73be61aSHans Rosenfeld }
2071