4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /*
27 * Contains DB walker functions, which are of type `db_wfunc_t';
28 *
29 * typedef boolean_t db_wfunc_t(void *cbarg, nvlist_t *db_nvl, char *buf,
30 * size_t bufsize, int *errp);
31 *
32 * ipadm_rw_db() walks through the data store, one line at a time and calls
33 * these call back functions with:
34 * `cbarg' - callback argument
35 * `db_nvl' - representing a line from DB in nvlist_t form
36 * `buf' - character buffer to hold modified line
37 * `bufsize'- size of the buffer
38 * `errp' - captures any error inside the walker function.
39 *
40 * All the 'write' callback functions modify `db_nvl' based on `cbarg' and
41 * copy string representation of `db_nvl' (using ipadm_nvlist2str()) into `buf'.
42 * To delete a line from the DB, buf[0] is set to `\0'. Inside ipadm_rw_db(),
43 * the modified `buf' is written back into DB.
60 /* SCF related property group names and property names */
61 #define IPMGMTD_APP_PG "ipmgmtd"
62 #define IPMGMTD_PROP_FBD "first_boot_done"
63 #define IPMGMTD_PROP_DBVER "datastore_version"
64 #define IPMGMTD_TRUESTR "true"
65
66 #define ATYPE "_atype" /* name of the address type nvpair */
67 #define FLAGS "_flags" /* name of the flags nvpair */
68
69 /*
70 * flag used by ipmgmt_persist_aobjmap() to indicate address type is
71 * IPADM_ADDR_IPV6_ADDRCONF.
72 */
73 #define IPMGMT_ATYPE_V6ACONF 0x1
74
75 extern pthread_rwlock_t ipmgmt_dbconf_lock;
76
77 /* signifies whether volatile copy of data store is in use */
78 static boolean_t ipmgmt_rdonly_root = B_FALSE;
79
80 /*
81 * Checks if the database nvl, `db_nvl' contains and matches ALL of the passed
82 * in private nvpairs `proto', `ifname' & `aobjname'.
83 */
84 static boolean_t
85 ipmgmt_nvlist_match(nvlist_t *db_nvl, const char *proto, const char *ifname,
86 const char *aobjname)
87 {
88 char *db_proto = NULL, *db_ifname = NULL;
89 char *db_aobjname = NULL;
90 nvpair_t *nvp;
91 char *name;
92
93 /* walk through db_nvl and retrieve all its private nvpairs */
94 for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
95 nvp = nvlist_next_nvpair(db_nvl, nvp)) {
96 name = nvpair_name(nvp);
97 if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
98 (void) nvpair_value_string(nvp, &db_proto);
99 else if (strcmp(IPADM_NVP_IFNAME, name) == 0)
305 } else {
306 buf[0] = '\0';
307 }
308
309 /* stop the search */
310 return (B_FALSE);
311 }
312
313 /*
314 * Input arguments can have IPADM_NVP_AOBJNAME or IPADM_NVP_IFNAME. A match is
315 * found, when one of the following occurs first.
316 * - the input aobjname matches the db aobjname. Return the db address.
317 * - the input interface matches the db interface. Return all the
318 * matching db lines with addresses.
319 */
320 /* ARGSUSED */
321 boolean_t
322 ipmgmt_db_getaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
323 int *errp)
324 {
325 ipmgmt_getaddr_cbarg_t *cbarg = arg;
326 char *db_aobjname = NULL;
327 char *db_ifname = NULL;
328 nvlist_t *db_addr = NULL;
329 char name[IPMGMT_STRSIZE];
330 nvpair_t *nvp;
331 boolean_t add_nvl = B_FALSE;
332
333 /* Parse db nvlist */
334 for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
335 nvp = nvlist_next_nvpair(db_nvl, nvp)) {
336 if (nvpair_type(nvp) == DATA_TYPE_NVLIST)
337 (void) nvpair_value_nvlist(nvp, &db_addr);
338 else if (strcmp(nvpair_name(nvp), IPADM_NVP_IFNAME) == 0)
339 (void) nvpair_value_string(nvp, &db_ifname);
340 else if (strcmp(nvpair_name(nvp), IPADM_NVP_AOBJNAME) == 0)
341 (void) nvpair_value_string(nvp, &db_aobjname);
342 }
343
344 if (db_aobjname == NULL) /* Not an address */
345 return (B_TRUE);
531 instrval);
532 if ((*errp = nvlist_add_string(db_nvl, name, pval)) != 0)
533 return (B_FALSE);
534 } else {
535 /* case of in-line update of a db entry */
536 if ((*errp = nvlist_add_string(db_nvl, name, instrval)) != 0)
537 return (B_FALSE);
538 }
539
540 (void) memset(buf, 0, buflen);
541 if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
542 /* buffer overflow */
543 *errp = ENOBUFS;
544 }
545
546 /* we updated the DB entry, so do not continue */
547 return (B_FALSE);
548 }
549
550 /*
551 * For the given `cbarg->cb_ifname' interface, retrieves any persistent
552 * interface information (used in 'ipadm show-if')
553 */
554 /* ARGSUSED */
555 boolean_t
556 ipmgmt_db_getif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
557 int *errp)
558 {
559 ipmgmt_getif_cbarg_t *cbarg = arg;
560 char *ifname = cbarg->cb_ifname;
561 char *intf = NULL;
562 ipadm_if_info_t *ifp = NULL;
563 sa_family_t af;
564 char *afstr;
565
566 *errp = 0;
567 if (nvlist_lookup_string(db_nvl, IPADM_NVP_FAMILY, &afstr) != 0 ||
568 nvlist_lookup_string(db_nvl, IPADM_NVP_IFNAME, &intf) != 0 ||
569 (ifname[0] != '\0' && strcmp(ifname, intf) != 0)) {
570 return (B_TRUE);
571 }
572 af = atoi(afstr);
573 for (ifp = cbarg->cb_ifinfo; ifp != NULL; ifp = ifp->ifi_next) {
574 if (strcmp(ifp->ifi_name, intf) == 0)
575 break;
576 }
577 if (ifp == NULL) {
578 ipadm_if_info_t *new;
579
580 if ((new = calloc(1, sizeof (*new))) == NULL) {
581 *errp = ENOMEM;
582 return (B_FALSE); /* don't continue the walk */
583 }
584 new->ifi_next = cbarg->cb_ifinfo;
585 cbarg->cb_ifinfo = new;
586 ifp = new;
587 (void) strlcpy(ifp->ifi_name, intf, sizeof (ifp->ifi_name));
588 }
589
590 if (af == AF_INET) {
591 ifp->ifi_pflags |= IFIF_IPV4;
592 } else {
593 assert(af == AF_INET6);
594 ifp->ifi_pflags |= IFIF_IPV6;
595 }
596
597 /* Terminate the walk if we found both v4 and v6 interfaces. */
598 if (ifname[0] != '\0' && (ifp->ifi_pflags & IFIF_IPV4) &&
599 (ifp->ifi_pflags & IFIF_IPV6))
600 return (B_FALSE);
601
602 return (B_TRUE);
603 }
604
605 /*
606 * Deletes those entries from the database for which interface name
607 * matches with the given `cbarg->cb_ifname'
608 */
609 /* ARGSUSED */
610 boolean_t
611 ipmgmt_db_resetif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
612 int *errp)
613 {
614 ipmgmt_if_cbarg_t *cbarg = arg;
615 boolean_t isv6 = (cbarg->cb_family == AF_INET6);
616 char *ifname = cbarg->cb_ifname;
617 char *modstr = NULL;
618 char *afstr;
619 char *aobjname;
620 uint_t proto;
621 ipmgmt_aobjmap_t *head;
622 boolean_t aobjfound = B_FALSE;
623
624 *errp = 0;
625
626 if (!ipmgmt_nvlist_contains(db_nvl, NULL, ifname, NULL))
627 return (B_TRUE);
628
629 if (nvlist_lookup_string(db_nvl, IPADM_NVP_FAMILY, &afstr) == 0) {
630 if (atoi(afstr) == cbarg->cb_family)
631 goto delete;
632 return (B_TRUE);
633 }
634
635 /* Reset all the interface configurations for 'ifname' */
636 if (isv6 && (nvlist_exists(db_nvl, IPADM_NVP_IPV6ADDR) ||
637 nvlist_exists(db_nvl, IPADM_NVP_INTFID))) {
638 goto delete;
639 }
640 if (!isv6 &&
641 (nvlist_exists(db_nvl, IPADM_NVP_IPV4ADDR) ||
642 nvlist_exists(db_nvl, IPADM_NVP_DHCP))) {
643 goto delete;
644 }
645
646 if (nvlist_lookup_string(db_nvl, IPADM_NVP_AOBJNAME, &aobjname) == 0) {
647 /*
648 * This must be an address property. Delete this
649 * line if there is a match in the address family.
650 */
651 head = aobjmap.aobjmap_head;
667 }
668
669 /*
670 * If we are removing both v4 and v6 interface, then we get rid of
671 * all the properties for that interface. On the other hand, if we
672 * are deleting only v4 instance of an interface, then we delete v4
673 * properties only.
674 */
675 if (nvlist_lookup_string(db_nvl, IPADM_NVP_PROTONAME, &modstr) == 0) {
676 proto = ipadm_str2proto(modstr);
677 switch (proto) {
678 case MOD_PROTO_IPV6:
679 if (isv6)
680 goto delete;
681 break;
682 case MOD_PROTO_IPV4:
683 if (!isv6)
684 goto delete;
685 break;
686 case MOD_PROTO_IP:
687 /* this should never be the case, today */
688 assert(0);
689 break;
690 }
691 }
692 /* Not found a match yet. Continue processing the db */
693 return (B_TRUE);
694 delete:
695 /* delete the line from the db */
696 buf[0] = '\0';
697 return (B_TRUE);
698 }
699
700 /*
701 * Deletes those entries from the database for which address object name
702 * matches with the given `cbarg->cb_aobjname'
703 */
704 /* ARGSUSED */
705 boolean_t
706 ipmgmt_db_resetaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
707 int *errp)
708 {
1668 /*
1669 * 'datastore_version' doesn't exist. Which means that we need to
1670 * upgrade the datastore. We will create 'datastore_version' and set
1671 * the version value to IPADM_DB_VERSION, after we upgrade the file.
1672 */
1673 return (bval);
1674 }
1675
1676 /*
1677 * This is called after the successful upgrade of the local data-store. With
1678 * the data-store upgraded to recent version we don't have to do anything on
1679 * subsequent reboots.
1680 */
1681 void
1682 ipmgmt_update_dbver(scf_resources_t *res)
1683 {
1684 int64_t version = IPADM_DB_VERSION;
1685
1686 (void) ipmgmt_set_scfprop(res, IPMGMTD_APP_PG,
1687 IPMGMTD_PROP_DBVER, &version, SCF_TYPE_INTEGER);
1688 }
|
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
25 */
26
27 /*
28 * Contains DB walker functions, which are of type `db_wfunc_t';
29 *
30 * typedef boolean_t db_wfunc_t(void *cbarg, nvlist_t *db_nvl, char *buf,
31 * size_t bufsize, int *errp);
32 *
33 * ipadm_rw_db() walks through the data store, one line at a time and calls
34 * these call back functions with:
35 * `cbarg' - callback argument
36 * `db_nvl' - representing a line from DB in nvlist_t form
37 * `buf' - character buffer to hold modified line
38 * `bufsize'- size of the buffer
39 * `errp' - captures any error inside the walker function.
40 *
41 * All the 'write' callback functions modify `db_nvl' based on `cbarg' and
42 * copy string representation of `db_nvl' (using ipadm_nvlist2str()) into `buf'.
43 * To delete a line from the DB, buf[0] is set to `\0'. Inside ipadm_rw_db(),
44 * the modified `buf' is written back into DB.
61 /* SCF related property group names and property names */
62 #define IPMGMTD_APP_PG "ipmgmtd"
63 #define IPMGMTD_PROP_FBD "first_boot_done"
64 #define IPMGMTD_PROP_DBVER "datastore_version"
65 #define IPMGMTD_TRUESTR "true"
66
67 #define ATYPE "_atype" /* name of the address type nvpair */
68 #define FLAGS "_flags" /* name of the flags nvpair */
69
70 /*
71 * flag used by ipmgmt_persist_aobjmap() to indicate address type is
72 * IPADM_ADDR_IPV6_ADDRCONF.
73 */
74 #define IPMGMT_ATYPE_V6ACONF 0x1
75
76 extern pthread_rwlock_t ipmgmt_dbconf_lock;
77
78 /* signifies whether volatile copy of data store is in use */
79 static boolean_t ipmgmt_rdonly_root = B_FALSE;
80
81 typedef int ipmgmt_if_updater_func_t(nvlist_t *, nvpair_t *, uint_t);
82
83 static ipmgmt_if_updater_func_t ipmgmt_if_family_updater;
84 static ipmgmt_if_updater_func_t ipmgmt_if_groupmembers_updater;
85
86 static int ipmgmt_get_ifinfo_nvl(const char *ifname, nvlist_t **if_info_nvl);
87
88 typedef struct {
89 const char *name;
90 ipmgmt_if_updater_func_t *func;
91 } ipmgmt_if_updater_ent_t;
92
93 static ipmgmt_if_updater_ent_t ipmgmt_if_updater_ent[] = {
94 {IPADM_NVP_FAMILIES, ipmgmt_if_family_updater},
95 {IPADM_NVP_MIFNAMES, ipmgmt_if_groupmembers_updater},
96 {NULL, NULL}
97 };
98
99 static ipmgmt_if_updater_ent_t *
100 ipmgmt_find_if_field_updater(const char *field_name)
101 {
102 int i;
103
104 for (i = 0; ipmgmt_if_updater_ent[i].name != NULL; i++) {
105 if (strcmp(field_name, ipmgmt_if_updater_ent[i].name) == 0) {
106 break;
107 }
108 }
109
110 return (&ipmgmt_if_updater_ent[i]);
111 }
112
113 static int
114 ipmgmt_if_groupmembers_updater(nvlist_t *db_nvl, nvpair_t *member_nvp,
115 uint_t flags)
116 {
117 char **members;
118 char *member;
119 char *out_memebers[256];
120 uint_t nelem = 0, cnt = 0;
121 int err;
122
123 if ((err = nvpair_value_string(member_nvp, &member)) != 0)
124 return (err);
125
126 err = nvlist_lookup_string_array(db_nvl, IPADM_NVP_MIFNAMES,
127 &members, &nelem);
128
129 if (err != 0 && (flags & IPMGMT_REMOVE))
130 return (ENOENT);
131
132 while (nelem--) {
133 if ((flags & IPMGMT_REMOVE) &&
134 (strcmp(member, members[nelem]) == 0))
135 continue;
136
137 if ((out_memebers[cnt] = strdup(members[nelem])) == NULL) {
138 err = ENOMEM;
139 goto fail;
140 }
141
142 cnt++;
143 }
144
145 if (flags & IPMGMT_APPEND) {
146 if ((out_memebers[cnt] = strdup(member)) == NULL) {
147 err = ENOMEM;
148 goto fail;
149 }
150 cnt++;
151 }
152
153 if (cnt == 0) {
154 err = nvlist_remove(db_nvl, IPADM_NVP_MIFNAMES,
155 DATA_TYPE_STRING_ARRAY);
156 } else {
157 err = nvlist_add_string_array(db_nvl, IPADM_NVP_MIFNAMES,
158 out_memebers, cnt);
159 }
160
161 fail:
162 while (cnt--)
163 free(out_memebers[cnt]);
164
165 return (err);
166 }
167
168 static int
169 ipmgmt_if_family_updater(nvlist_t *db_nvl, nvpair_t *families_nvp, uint_t flags)
170 {
171 uint16_t *families;
172 uint_t nelem = 0;
173 int err;
174
175 if ((err = nvpair_value_uint16_array(families_nvp, &families,
176 &nelem)) != 0)
177 return (err);
178
179 return (ipmgmt_update_family_nvp(db_nvl, families[0], flags));
180 }
181
182 int
183 ipmgmt_update_family_nvp(nvlist_t *nvl, sa_family_t af, uint_t flags)
184 {
185 uint16_t *families = NULL;
186 uint16_t out_families[2];
187 uint_t nelem = 0, cnt;
188 int err;
189
190 err = nvlist_lookup_uint16_array(nvl, IPADM_NVP_FAMILIES,
191 &families, &nelem);
192 if (err != 0 && (flags & IPMGMT_REMOVE)) {
193 return (ENOENT);
194 }
195
196 if (flags & IPMGMT_APPEND) {
197 if (families != NULL) {
198 if (nelem == 2 || families[0] == af) {
199 return (EEXIST);
200 }
201 out_families[0] = families[0];
202 out_families[1] = af;
203 cnt = 2;
204 } else {
205 out_families[0] = af;
206 cnt = 1;
207 }
208 } else {
209 assert(nelem == 1 || nelem == 2);
210 cnt = 0;
211 while (nelem--) {
212 if (families[nelem] != af) {
213 out_families[cnt] = families[nelem];
214 cnt++;
215 }
216 }
217 }
218
219 if (cnt != 0) {
220 return (nvlist_add_uint16_array(nvl, IPADM_NVP_FAMILIES,
221 out_families, cnt));
222 }
223 return (nvlist_remove(nvl, IPADM_NVP_FAMILIES, DATA_TYPE_UINT16_ARRAY));
224 }
225
226 /*
227 * Checks if the database nvl, `db_nvl' contains and matches ALL of the passed
228 * in private nvpairs `proto', `ifname' & `aobjname'.
229 */
230 static boolean_t
231 ipmgmt_nvlist_match(nvlist_t *db_nvl, const char *proto, const char *ifname,
232 const char *aobjname)
233 {
234 char *db_proto = NULL, *db_ifname = NULL;
235 char *db_aobjname = NULL;
236 nvpair_t *nvp;
237 char *name;
238
239 /* walk through db_nvl and retrieve all its private nvpairs */
240 for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
241 nvp = nvlist_next_nvpair(db_nvl, nvp)) {
242 name = nvpair_name(nvp);
243 if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
244 (void) nvpair_value_string(nvp, &db_proto);
245 else if (strcmp(IPADM_NVP_IFNAME, name) == 0)
451 } else {
452 buf[0] = '\0';
453 }
454
455 /* stop the search */
456 return (B_FALSE);
457 }
458
459 /*
460 * Input arguments can have IPADM_NVP_AOBJNAME or IPADM_NVP_IFNAME. A match is
461 * found, when one of the following occurs first.
462 * - the input aobjname matches the db aobjname. Return the db address.
463 * - the input interface matches the db interface. Return all the
464 * matching db lines with addresses.
465 */
466 /* ARGSUSED */
467 boolean_t
468 ipmgmt_db_getaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
469 int *errp)
470 {
471 ipmgmt_get_cbarg_t *cbarg = arg;
472 char *db_aobjname = NULL;
473 char *db_ifname = NULL;
474 nvlist_t *db_addr = NULL;
475 char name[IPMGMT_STRSIZE];
476 nvpair_t *nvp;
477 boolean_t add_nvl = B_FALSE;
478
479 /* Parse db nvlist */
480 for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
481 nvp = nvlist_next_nvpair(db_nvl, nvp)) {
482 if (nvpair_type(nvp) == DATA_TYPE_NVLIST)
483 (void) nvpair_value_nvlist(nvp, &db_addr);
484 else if (strcmp(nvpair_name(nvp), IPADM_NVP_IFNAME) == 0)
485 (void) nvpair_value_string(nvp, &db_ifname);
486 else if (strcmp(nvpair_name(nvp), IPADM_NVP_AOBJNAME) == 0)
487 (void) nvpair_value_string(nvp, &db_aobjname);
488 }
489
490 if (db_aobjname == NULL) /* Not an address */
491 return (B_TRUE);
677 instrval);
678 if ((*errp = nvlist_add_string(db_nvl, name, pval)) != 0)
679 return (B_FALSE);
680 } else {
681 /* case of in-line update of a db entry */
682 if ((*errp = nvlist_add_string(db_nvl, name, instrval)) != 0)
683 return (B_FALSE);
684 }
685
686 (void) memset(buf, 0, buflen);
687 if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
688 /* buffer overflow */
689 *errp = ENOBUFS;
690 }
691
692 /* we updated the DB entry, so do not continue */
693 return (B_FALSE);
694 }
695
696 /*
697 * This function is used to update a DB line that describes
698 * an interface, its family and group interface
699 *
700 */
701 boolean_t
702 ipmgmt_db_update_if(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
703 int *errp)
704 {
705 ipadm_dbwrite_cbarg_t *cb = arg;
706 nvlist_t *in_nvl = cb->dbw_nvl;
707 uint_t flags = cb->dbw_flags;
708 nvpair_t *nvp;
709 char *name;
710 ipmgmt_if_updater_ent_t *updater;
711 char *member = NULL;
712 char *gifname = NULL;
713 char *db_line_if_name;
714
715
716 *errp = 0;
717
718 /* Only one flag */
719 if ((flags & (IPMGMT_APPEND | IPMGMT_REMOVE)) == 0 ||
720 ((flags & IPMGMT_APPEND) && (flags & IPMGMT_REMOVE))) {
721 *errp = EINVAL;
722 return (B_FALSE);
723 }
724
725 if (!nvlist_exists(db_nvl, IPADM_NVP_FAMILIES))
726 return (B_TRUE);
727
728 if (nvlist_lookup_string(db_nvl,
729 IPADM_NVP_IFNAME, &db_line_if_name) == 0 &&
730 nvlist_lookup_string(in_nvl, IPADM_NVP_GIFNAME, &gifname) == 0 &&
731 nvlist_lookup_string(in_nvl, IPADM_NVP_MIFNAMES, &member) == 0 &&
732 strcmp(db_line_if_name, member) == 0) {
733 if (flags & IPMGMT_APPEND) {
734 if ((*errp = nvlist_add_string(db_nvl,
735 IPADM_NVP_GIFNAME, gifname)) != 0)
736 return (B_FALSE);
737 } else {
738 if ((*errp = nvlist_remove(db_nvl, IPADM_NVP_GIFNAME,
739 DATA_TYPE_STRING)) != 0)
740 return (B_FALSE);
741 }
742 cb->dbw_flags &= ~IPMGMT_UPDATE_IPMP;
743 goto done;
744 }
745
746 if (!ipmgmt_nvlist_intersects(db_nvl, in_nvl))
747 return (B_TRUE);
748
749
750 for (nvp = nvlist_next_nvpair(in_nvl, NULL); nvp != NULL;
751 nvp = nvlist_next_nvpair(in_nvl, nvp)) {
752
753 name = nvpair_name(nvp);
754 if (strcmp(name, IPADM_NVP_FAMILIES) != 0 &&
755 strcmp(name, IPADM_NVP_MIFNAMES) != 0)
756 continue;
757
758 updater = ipmgmt_find_if_field_updater(name);
759 assert(updater != NULL);
760 *errp = (*updater->func)(db_nvl, nvp, flags);
761 if (*errp != 0)
762 return (B_FALSE);
763 }
764
765 cb->dbw_flags &= ~IPMGMT_UPDATE_IF;
766
767 done:
768 (void) memset(buf, 0, buflen);
769 if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
770 *errp = ENOBUFS;
771 return (B_FALSE);
772 }
773
774 /* we finished all operations ???, so do not continue */
775 if ((cb->dbw_flags & (IPMGMT_UPDATE_IF | IPMGMT_UPDATE_IPMP)) == 0)
776 return (B_FALSE);
777
778 return (B_TRUE);
779 }
780
781 /*
782 * For the given `cbarg->cb_ifname' interface retrieves
783 * the nvlist that represents the persistent interface information
784 * The nvlist contains:
785 * IPADM_NVP_IFNAME
786 * IPADM_NVP_FAMILIES
787 * IPADM_NVP_IF_CLASS
788 *
789 * (used in 'ipadm show-if')
790 */
791 /* ARGSUSED */
792 boolean_t
793 ipmgmt_db_getif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
794 int *errp)
795 {
796 ipmgmt_get_cbarg_t *cbarg = arg;
797 char *ifname = cbarg->cb_ifname;
798 nvpair_t *nvp;
799 char *db_ifname = NULL;
800 uint16_t *db_families = NULL;
801 uint_t nelem = 0;
802
803 /* Parse db nvlist */
804 for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
805 nvp = nvlist_next_nvpair(db_nvl, nvp)) {
806
807 if (strcmp(nvpair_name(nvp), IPADM_NVP_IFNAME) == 0)
808 (void) nvpair_value_string(nvp, &db_ifname);
809 else if (strcmp(nvpair_name(nvp), IPADM_NVP_FAMILIES) == 0)
810 (void) nvpair_value_uint16_array(nvp,
811 &db_families, &nelem);
812 }
813
814 if (db_ifname == NULL || db_families == NULL)
815 return (B_TRUE);
816
817 if (ifname != NULL && ifname[0] != '\0' &&
818 strcmp(ifname, db_ifname) != 0)
819 return (B_TRUE);
820
821 *errp = nvlist_add_nvlist(cbarg->cb_onvl, db_ifname, db_nvl);
822 if (*errp == 0)
823 cbarg->cb_ocnt++;
824
825 if (ifname != NULL && ifname[0] != '\0')
826 return (B_FALSE);
827
828 return (B_TRUE);
829 }
830
831 /*
832 * Deletes those entries from the database for which interface name
833 * matches with the given `cbarg->cb_ifname'
834 */
835 /* ARGSUSED */
836 boolean_t
837 ipmgmt_db_resetif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
838 int *errp)
839 {
840 ipmgmt_if_cbarg_t *cbarg = arg;
841 boolean_t isv6 = (cbarg->cb_family == AF_INET6);
842 char *ifname = cbarg->cb_ifname;
843 char *modstr = NULL;
844 char *aobjname;
845 uint_t proto;
846 ipmgmt_aobjmap_t *head;
847 boolean_t aobjfound = B_FALSE;
848
849 *errp = 0;
850
851 if (!ipmgmt_nvlist_contains(db_nvl, NULL, ifname, NULL))
852 return (B_TRUE);
853
854 if (nvlist_exists(db_nvl, IPADM_NVP_FAMILIES)) {
855
856 if ((*errp = ipmgmt_update_family_nvp(db_nvl, cbarg->cb_family,
857 IPMGMT_REMOVE)) != 0) {
858 return (B_FALSE);
859 }
860
861 if (cbarg->cb_family == AF_INET) {
862 cbarg->cb_ipv4exists = B_FALSE;
863 } else {
864 assert(cbarg->cb_family == AF_INET6);
865 cbarg->cb_ipv6exists = B_FALSE;
866 }
867 if (!nvlist_exists(db_nvl, IPADM_NVP_FAMILIES)) {
868 cbarg->cb_ipv4exists = B_FALSE;
869 cbarg->cb_ipv6exists = B_FALSE;
870 goto delete;
871 }
872 /* Otherwise need to reconstruct this string */
873 (void) memset(buf, 0, buflen);
874 if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
875 /* buffer overflow */
876 *errp = ENOBUFS;
877 return (B_FALSE);
878 }
879 return (B_TRUE);
880 }
881
882 /* Reset all the interface configurations for 'ifname' */
883 if (isv6 && (nvlist_exists(db_nvl, IPADM_NVP_IPV6ADDR) ||
884 nvlist_exists(db_nvl, IPADM_NVP_INTFID))) {
885 goto delete;
886 }
887 if (!isv6 &&
888 (nvlist_exists(db_nvl, IPADM_NVP_IPV4ADDR) ||
889 nvlist_exists(db_nvl, IPADM_NVP_DHCP))) {
890 goto delete;
891 }
892
893 if (nvlist_lookup_string(db_nvl, IPADM_NVP_AOBJNAME, &aobjname) == 0) {
894 /*
895 * This must be an address property. Delete this
896 * line if there is a match in the address family.
897 */
898 head = aobjmap.aobjmap_head;
914 }
915
916 /*
917 * If we are removing both v4 and v6 interface, then we get rid of
918 * all the properties for that interface. On the other hand, if we
919 * are deleting only v4 instance of an interface, then we delete v4
920 * properties only.
921 */
922 if (nvlist_lookup_string(db_nvl, IPADM_NVP_PROTONAME, &modstr) == 0) {
923 proto = ipadm_str2proto(modstr);
924 switch (proto) {
925 case MOD_PROTO_IPV6:
926 if (isv6)
927 goto delete;
928 break;
929 case MOD_PROTO_IPV4:
930 if (!isv6)
931 goto delete;
932 break;
933 case MOD_PROTO_IP:
934 if (!cbarg->cb_ipv4exists && !cbarg->cb_ipv6exists)
935 goto delete;
936 break;
937 }
938 }
939 /* Not found a match yet. Continue processing the db */
940 return (B_TRUE);
941 delete:
942 /* delete the line from the db */
943 buf[0] = '\0';
944 return (B_TRUE);
945 }
946
947 /*
948 * Deletes those entries from the database for which address object name
949 * matches with the given `cbarg->cb_aobjname'
950 */
951 /* ARGSUSED */
952 boolean_t
953 ipmgmt_db_resetaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
954 int *errp)
955 {
1915 /*
1916 * 'datastore_version' doesn't exist. Which means that we need to
1917 * upgrade the datastore. We will create 'datastore_version' and set
1918 * the version value to IPADM_DB_VERSION, after we upgrade the file.
1919 */
1920 return (bval);
1921 }
1922
1923 /*
1924 * This is called after the successful upgrade of the local data-store. With
1925 * the data-store upgraded to recent version we don't have to do anything on
1926 * subsequent reboots.
1927 */
1928 void
1929 ipmgmt_update_dbver(scf_resources_t *res)
1930 {
1931 int64_t version = IPADM_DB_VERSION;
1932
1933 (void) ipmgmt_set_scfprop(res, IPMGMTD_APP_PG,
1934 IPMGMTD_PROP_DBVER, &version, SCF_TYPE_INTEGER);
1935 }
1936
1937 /*
1938 * Return TRUE if `ifname' has persistent configuration for the `af' address
1939 * family in the datastore.
1940 * It is possible to call the function with af == AF_UNSPEC, so in this case
1941 * the function returns TRUE if either AF_INET or AF_INET6 interface exists
1942 */
1943 boolean_t
1944 ipmgmt_persist_if_exists(const char *ifname, sa_family_t af)
1945 {
1946 boolean_t exists = B_FALSE;
1947 nvlist_t *if_info_nvl;
1948 uint16_t *families = NULL;
1949 sa_family_t af_db;
1950 uint_t nelem = 0;
1951
1952 if (ipmgmt_get_ifinfo_nvl(ifname, &if_info_nvl) != 0)
1953 goto done;
1954
1955 if (nvlist_lookup_uint16_array(if_info_nvl, IPADM_NVP_FAMILIES,
1956 &families, &nelem) != 0)
1957 goto done;
1958
1959 while (nelem--) {
1960 af_db = families[nelem];
1961 if (af_db == af || (af == AF_UNSPEC &&
1962 (af_db == AF_INET || af_db == AF_INET6))) {
1963 exists = B_TRUE;
1964 break;
1965 }
1966 }
1967
1968 done:
1969 if (if_info_nvl != NULL)
1970 nvlist_free(if_info_nvl);
1971
1972 return (exists);
1973 }
1974
1975 /*
1976 * Retrieves the membership information for the requested mif_name
1977 * if mif_name is a memeber of a IPMP group, then gif_name will contain
1978 * the name of IPMP group interface, otherwise the variable will be empty
1979 */
1980 void
1981 ipmgmt_get_group_interface(const char *mif_name, char *gif_name, size_t size)
1982 {
1983 char *gif_name_from_nvl;
1984 nvlist_t *if_info_nvl;
1985
1986 gif_name[0] = '\0';
1987
1988 if (ipmgmt_get_ifinfo_nvl(mif_name, &if_info_nvl) != 0)
1989 goto done;
1990
1991 if (nvlist_lookup_string(if_info_nvl, IPADM_NVP_GIFNAME,
1992 &gif_name_from_nvl) != 0)
1993 goto done;
1994
1995 (void) strlcpy(gif_name, gif_name_from_nvl, size);
1996
1997 done:
1998 if (if_info_nvl != NULL)
1999 nvlist_free(if_info_nvl);
2000 }
2001
2002 static int
2003 ipmgmt_get_ifinfo_nvl(const char *ifname, nvlist_t **if_info_nvl)
2004 {
2005 ipmgmt_get_cbarg_t cbarg;
2006 nvpair_t *nvp;
2007 nvlist_t *nvl;
2008 int err;
2009
2010 cbarg.cb_ifname = NULL;
2011 cbarg.cb_aobjname = NULL;
2012 cbarg.cb_ocnt = 0;
2013
2014 if ((err = nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0)) != 0)
2015 goto done;
2016
2017 err = ipmgmt_db_walk(ipmgmt_db_getif, &cbarg, IPADM_DB_READ);
2018 if (err == ENOENT && cbarg.cb_ocnt > 0)
2019 err = 0;
2020
2021 if (err != 0)
2022 goto done;
2023
2024 for (nvp = nvlist_next_nvpair(cbarg.cb_onvl, NULL); nvp != NULL;
2025 nvp = nvlist_next_nvpair(cbarg.cb_onvl, nvp)) {
2026
2027 if (strcmp(nvpair_name(nvp), ifname) != 0)
2028 continue;
2029
2030 if ((err = nvpair_value_nvlist(nvp, &nvl)) != 0 ||
2031 (err = nvlist_dup(nvl, if_info_nvl, NV_UNIQUE_NAME)) != 0)
2032 *if_info_nvl = NULL;
2033
2034 break;
2035 }
2036
2037 done:
2038 nvlist_free(cbarg.cb_onvl);
2039
2040 return (err);
2041 }
|