Print this page
Commit IPMP changes

*** 19,28 **** --- 19,29 ---- * CDDL HEADER END */ /* * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2014 Nexenta Systems, Inc. All rights reserved. */ /* * Contains DB walker functions, which are of type `db_wfunc_t'; *
*** 75,84 **** --- 76,230 ---- extern pthread_rwlock_t ipmgmt_dbconf_lock; /* signifies whether volatile copy of data store is in use */ static boolean_t ipmgmt_rdonly_root = B_FALSE; + typedef int ipmgmt_if_updater_func_t(nvlist_t *, nvpair_t *, uint_t); + + static ipmgmt_if_updater_func_t ipmgmt_if_family_updater; + static ipmgmt_if_updater_func_t ipmgmt_if_groupmembers_updater; + + static int ipmgmt_get_ifinfo_nvl(const char *ifname, nvlist_t **if_info_nvl); + + typedef struct { + const char *name; + ipmgmt_if_updater_func_t *func; + } ipmgmt_if_updater_ent_t; + + static ipmgmt_if_updater_ent_t ipmgmt_if_updater_ent[] = { + {IPADM_NVP_FAMILIES, ipmgmt_if_family_updater}, + {IPADM_NVP_MIFNAMES, ipmgmt_if_groupmembers_updater}, + {NULL, NULL} + }; + + static ipmgmt_if_updater_ent_t * + ipmgmt_find_if_field_updater(const char *field_name) + { + int i; + + for (i = 0; ipmgmt_if_updater_ent[i].name != NULL; i++) { + if (strcmp(field_name, ipmgmt_if_updater_ent[i].name) == 0) { + break; + } + } + + return (&ipmgmt_if_updater_ent[i]); + } + + static int + ipmgmt_if_groupmembers_updater(nvlist_t *db_nvl, nvpair_t *member_nvp, + uint_t flags) + { + char **members; + char *member; + char *out_memebers[256]; + uint_t nelem = 0, cnt = 0; + int err; + + if ((err = nvpair_value_string(member_nvp, &member)) != 0) + return (err); + + err = nvlist_lookup_string_array(db_nvl, IPADM_NVP_MIFNAMES, + &members, &nelem); + + if (err != 0 && (flags & IPMGMT_REMOVE)) + return (ENOENT); + + while (nelem--) { + if ((flags & IPMGMT_REMOVE) && + (strcmp(member, members[nelem]) == 0)) + continue; + + if ((out_memebers[cnt] = strdup(members[nelem])) == NULL) { + err = ENOMEM; + goto fail; + } + + cnt++; + } + + if (flags & IPMGMT_APPEND) { + if ((out_memebers[cnt] = strdup(member)) == NULL) { + err = ENOMEM; + goto fail; + } + cnt++; + } + + if (cnt == 0) { + err = nvlist_remove(db_nvl, IPADM_NVP_MIFNAMES, + DATA_TYPE_STRING_ARRAY); + } else { + err = nvlist_add_string_array(db_nvl, IPADM_NVP_MIFNAMES, + out_memebers, cnt); + } + + fail: + while (cnt--) + free(out_memebers[cnt]); + + return (err); + } + + static int + ipmgmt_if_family_updater(nvlist_t *db_nvl, nvpair_t *families_nvp, uint_t flags) + { + uint16_t *families; + uint_t nelem = 0; + int err; + + if ((err = nvpair_value_uint16_array(families_nvp, &families, + &nelem)) != 0) + return (err); + + return (ipmgmt_update_family_nvp(db_nvl, families[0], flags)); + } + + int + ipmgmt_update_family_nvp(nvlist_t *nvl, sa_family_t af, uint_t flags) + { + uint16_t *families = NULL; + uint16_t out_families[2]; + uint_t nelem = 0, cnt; + int err; + + err = nvlist_lookup_uint16_array(nvl, IPADM_NVP_FAMILIES, + &families, &nelem); + if (err != 0 && (flags & IPMGMT_REMOVE)) { + return (ENOENT); + } + + if (flags & IPMGMT_APPEND) { + if (families != NULL) { + if (nelem == 2 || families[0] == af) { + return (EEXIST); + } + out_families[0] = families[0]; + out_families[1] = af; + cnt = 2; + } else { + out_families[0] = af; + cnt = 1; + } + } else { + assert(nelem == 1 || nelem == 2); + cnt = 0; + while (nelem--) { + if (families[nelem] != af) { + out_families[cnt] = families[nelem]; + cnt++; + } + } + } + + if (cnt != 0) { + return (nvlist_add_uint16_array(nvl, IPADM_NVP_FAMILIES, + out_families, cnt)); + } + return (nvlist_remove(nvl, IPADM_NVP_FAMILIES, DATA_TYPE_UINT16_ARRAY)); + } + /* * Checks if the database nvl, `db_nvl' contains and matches ALL of the passed * in private nvpairs `proto', `ifname' & `aobjname'. */ static boolean_t
*** 320,330 **** /* ARGSUSED */ boolean_t ipmgmt_db_getaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen, int *errp) { ! ipmgmt_getaddr_cbarg_t *cbarg = arg; char *db_aobjname = NULL; char *db_ifname = NULL; nvlist_t *db_addr = NULL; char name[IPMGMT_STRSIZE]; nvpair_t *nvp; --- 466,476 ---- /* ARGSUSED */ boolean_t ipmgmt_db_getaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen, int *errp) { ! ipmgmt_get_cbarg_t *cbarg = arg; char *db_aobjname = NULL; char *db_ifname = NULL; nvlist_t *db_addr = NULL; char name[IPMGMT_STRSIZE]; nvpair_t *nvp;
*** 546,604 **** /* we updated the DB entry, so do not continue */ return (B_FALSE); } /* ! * For the given `cbarg->cb_ifname' interface, retrieves any persistent ! * interface information (used in 'ipadm show-if') */ - /* ARGSUSED */ boolean_t ! ipmgmt_db_getif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen, int *errp) { ! ipmgmt_getif_cbarg_t *cbarg = arg; ! char *ifname = cbarg->cb_ifname; ! char *intf = NULL; ! ipadm_if_info_t *ifp = NULL; ! sa_family_t af; ! char *afstr; *errp = 0; ! if (nvlist_lookup_string(db_nvl, IPADM_NVP_FAMILY, &afstr) != 0 || ! nvlist_lookup_string(db_nvl, IPADM_NVP_IFNAME, &intf) != 0 || ! (ifname[0] != '\0' && strcmp(ifname, intf) != 0)) { return (B_TRUE); } ! af = atoi(afstr); ! for (ifp = cbarg->cb_ifinfo; ifp != NULL; ifp = ifp->ifi_next) { ! if (strcmp(ifp->ifi_name, intf) == 0) ! break; } - if (ifp == NULL) { - ipadm_if_info_t *new; ! if ((new = calloc(1, sizeof (*new))) == NULL) { ! *errp = ENOMEM; ! return (B_FALSE); /* don't continue the walk */ } ! new->ifi_next = cbarg->cb_ifinfo; ! cbarg->cb_ifinfo = new; ! ifp = new; ! (void) strlcpy(ifp->ifi_name, intf, sizeof (ifp->ifi_name)); } ! if (af == AF_INET) { ! ifp->ifi_pflags |= IFIF_IPV4; ! } else { ! assert(af == AF_INET6); ! ifp->ifi_pflags |= IFIF_IPV6; } ! /* Terminate the walk if we found both v4 and v6 interfaces. */ ! if (ifname[0] != '\0' && (ifp->ifi_pflags & IFIF_IPV4) && ! (ifp->ifi_pflags & IFIF_IPV6)) return (B_FALSE); return (B_TRUE); } --- 692,830 ---- /* we updated the DB entry, so do not continue */ return (B_FALSE); } /* ! * This function is used to update a DB line that describes ! * an interface, its family and group interface ! * */ boolean_t ! ipmgmt_db_update_if(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen, int *errp) { ! ipadm_dbwrite_cbarg_t *cb = arg; ! nvlist_t *in_nvl = cb->dbw_nvl; ! uint_t flags = cb->dbw_flags; ! nvpair_t *nvp; ! char *name; ! ipmgmt_if_updater_ent_t *updater; ! char *member = NULL; ! char *gifname = NULL; ! char *db_line_if_name; + *errp = 0; ! ! /* Only one flag */ ! if ((flags & (IPMGMT_APPEND | IPMGMT_REMOVE)) == 0 || ! ((flags & IPMGMT_APPEND) && (flags & IPMGMT_REMOVE))) { ! *errp = EINVAL; ! return (B_FALSE); ! } ! ! if (!nvlist_exists(db_nvl, IPADM_NVP_FAMILIES)) return (B_TRUE); + + if (nvlist_lookup_string(db_nvl, + IPADM_NVP_IFNAME, &db_line_if_name) == 0 && + nvlist_lookup_string(in_nvl, IPADM_NVP_GIFNAME, &gifname) == 0 && + nvlist_lookup_string(in_nvl, IPADM_NVP_MIFNAMES, &member) == 0 && + strcmp(db_line_if_name, member) == 0) { + if (flags & IPMGMT_APPEND) { + if ((*errp = nvlist_add_string(db_nvl, + IPADM_NVP_GIFNAME, gifname)) != 0) + return (B_FALSE); + } else { + if ((*errp = nvlist_remove(db_nvl, IPADM_NVP_GIFNAME, + DATA_TYPE_STRING)) != 0) + return (B_FALSE); } ! cb->dbw_flags &= ~IPMGMT_UPDATE_IPMP; ! goto done; } ! if (!ipmgmt_nvlist_intersects(db_nvl, in_nvl)) ! return (B_TRUE); ! ! ! for (nvp = nvlist_next_nvpair(in_nvl, NULL); nvp != NULL; ! nvp = nvlist_next_nvpair(in_nvl, nvp)) { ! ! name = nvpair_name(nvp); ! if (strcmp(name, IPADM_NVP_FAMILIES) != 0 && ! strcmp(name, IPADM_NVP_MIFNAMES) != 0) ! continue; ! ! updater = ipmgmt_find_if_field_updater(name); ! assert(updater != NULL); ! *errp = (*updater->func)(db_nvl, nvp, flags); ! if (*errp != 0) ! return (B_FALSE); } ! ! cb->dbw_flags &= ~IPMGMT_UPDATE_IF; ! ! done: ! (void) memset(buf, 0, buflen); ! if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) { ! *errp = ENOBUFS; ! return (B_FALSE); } ! /* we finished all operations ???, so do not continue */ ! if ((cb->dbw_flags & (IPMGMT_UPDATE_IF | IPMGMT_UPDATE_IPMP)) == 0) ! return (B_FALSE); ! ! return (B_TRUE); ! } ! ! /* ! * For the given `cbarg->cb_ifname' interface retrieves ! * the nvlist that represents the persistent interface information ! * The nvlist contains: ! * IPADM_NVP_IFNAME ! * IPADM_NVP_FAMILIES ! * IPADM_NVP_IF_CLASS ! * ! * (used in 'ipadm show-if') ! */ ! /* ARGSUSED */ ! boolean_t ! ipmgmt_db_getif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen, ! int *errp) ! { ! ipmgmt_get_cbarg_t *cbarg = arg; ! char *ifname = cbarg->cb_ifname; ! nvpair_t *nvp; ! char *db_ifname = NULL; ! uint16_t *db_families = NULL; ! uint_t nelem = 0; ! ! /* Parse db nvlist */ ! for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL; ! nvp = nvlist_next_nvpair(db_nvl, nvp)) { ! ! if (strcmp(nvpair_name(nvp), IPADM_NVP_IFNAME) == 0) ! (void) nvpair_value_string(nvp, &db_ifname); ! else if (strcmp(nvpair_name(nvp), IPADM_NVP_FAMILIES) == 0) ! (void) nvpair_value_uint16_array(nvp, ! &db_families, &nelem); } ! if (db_ifname == NULL || db_families == NULL) ! return (B_TRUE); ! ! if (ifname != NULL && ifname[0] != '\0' && ! strcmp(ifname, db_ifname) != 0) ! return (B_TRUE); ! ! *errp = nvlist_add_nvlist(cbarg->cb_onvl, db_ifname, db_nvl); ! if (*errp == 0) ! cbarg->cb_ocnt++; ! ! if (ifname != NULL && ifname[0] != '\0') return (B_FALSE); return (B_TRUE); }
*** 613,623 **** { ipmgmt_if_cbarg_t *cbarg = arg; boolean_t isv6 = (cbarg->cb_family == AF_INET6); char *ifname = cbarg->cb_ifname; char *modstr = NULL; - char *afstr; char *aobjname; uint_t proto; ipmgmt_aobjmap_t *head; boolean_t aobjfound = B_FALSE; --- 839,848 ----
*** 624,636 **** *errp = 0; if (!ipmgmt_nvlist_contains(db_nvl, NULL, ifname, NULL)) return (B_TRUE); ! if (nvlist_lookup_string(db_nvl, IPADM_NVP_FAMILY, &afstr) == 0) { ! if (atoi(afstr) == cbarg->cb_family) goto delete; return (B_TRUE); } /* Reset all the interface configurations for 'ifname' */ if (isv6 && (nvlist_exists(db_nvl, IPADM_NVP_IPV6ADDR) || --- 849,883 ---- *errp = 0; if (!ipmgmt_nvlist_contains(db_nvl, NULL, ifname, NULL)) return (B_TRUE); ! if (nvlist_exists(db_nvl, IPADM_NVP_FAMILIES)) { ! ! if ((*errp = ipmgmt_update_family_nvp(db_nvl, cbarg->cb_family, ! IPMGMT_REMOVE)) != 0) { ! return (B_FALSE); ! } ! ! if (cbarg->cb_family == AF_INET) { ! cbarg->cb_ipv4exists = B_FALSE; ! } else { ! assert(cbarg->cb_family == AF_INET6); ! cbarg->cb_ipv6exists = B_FALSE; ! } ! if (!nvlist_exists(db_nvl, IPADM_NVP_FAMILIES)) { ! cbarg->cb_ipv4exists = B_FALSE; ! cbarg->cb_ipv6exists = B_FALSE; goto delete; + } + /* Otherwise need to reconstruct this string */ + (void) memset(buf, 0, buflen); + if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) { + /* buffer overflow */ + *errp = ENOBUFS; + return (B_FALSE); + } return (B_TRUE); } /* Reset all the interface configurations for 'ifname' */ if (isv6 && (nvlist_exists(db_nvl, IPADM_NVP_IPV6ADDR) ||
*** 682,693 **** case MOD_PROTO_IPV4: if (!isv6) goto delete; break; case MOD_PROTO_IP: ! /* this should never be the case, today */ ! assert(0); break; } } /* Not found a match yet. Continue processing the db */ return (B_TRUE); --- 929,940 ---- case MOD_PROTO_IPV4: if (!isv6) goto delete; break; case MOD_PROTO_IP: ! if (!cbarg->cb_ipv4exists && !cbarg->cb_ipv6exists) ! goto delete; break; } } /* Not found a match yet. Continue processing the db */ return (B_TRUE);
*** 1683,1688 **** --- 1930,2041 ---- { int64_t version = IPADM_DB_VERSION; (void) ipmgmt_set_scfprop(res, IPMGMTD_APP_PG, IPMGMTD_PROP_DBVER, &version, SCF_TYPE_INTEGER); + } + + /* + * Return TRUE if `ifname' has persistent configuration for the `af' address + * family in the datastore. + * It is possible to call the function with af == AF_UNSPEC, so in this case + * the function returns TRUE if either AF_INET or AF_INET6 interface exists + */ + boolean_t + ipmgmt_persist_if_exists(const char *ifname, sa_family_t af) + { + boolean_t exists = B_FALSE; + nvlist_t *if_info_nvl; + uint16_t *families = NULL; + sa_family_t af_db; + uint_t nelem = 0; + + if (ipmgmt_get_ifinfo_nvl(ifname, &if_info_nvl) != 0) + goto done; + + if (nvlist_lookup_uint16_array(if_info_nvl, IPADM_NVP_FAMILIES, + &families, &nelem) != 0) + goto done; + + while (nelem--) { + af_db = families[nelem]; + if (af_db == af || (af == AF_UNSPEC && + (af_db == AF_INET || af_db == AF_INET6))) { + exists = B_TRUE; + break; + } + } + + done: + if (if_info_nvl != NULL) + nvlist_free(if_info_nvl); + + return (exists); + } + + /* + * Retrieves the membership information for the requested mif_name + * if mif_name is a memeber of a IPMP group, then gif_name will contain + * the name of IPMP group interface, otherwise the variable will be empty + */ + void + ipmgmt_get_group_interface(const char *mif_name, char *gif_name, size_t size) + { + char *gif_name_from_nvl; + nvlist_t *if_info_nvl; + + gif_name[0] = '\0'; + + if (ipmgmt_get_ifinfo_nvl(mif_name, &if_info_nvl) != 0) + goto done; + + if (nvlist_lookup_string(if_info_nvl, IPADM_NVP_GIFNAME, + &gif_name_from_nvl) != 0) + goto done; + + (void) strlcpy(gif_name, gif_name_from_nvl, size); + + done: + if (if_info_nvl != NULL) + nvlist_free(if_info_nvl); + } + + static int + ipmgmt_get_ifinfo_nvl(const char *ifname, nvlist_t **if_info_nvl) + { + ipmgmt_get_cbarg_t cbarg; + nvpair_t *nvp; + nvlist_t *nvl; + int err; + + cbarg.cb_ifname = NULL; + cbarg.cb_aobjname = NULL; + cbarg.cb_ocnt = 0; + + if ((err = nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0)) != 0) + goto done; + + err = ipmgmt_db_walk(ipmgmt_db_getif, &cbarg, IPADM_DB_READ); + if (err == ENOENT && cbarg.cb_ocnt > 0) + err = 0; + + if (err != 0) + goto done; + + for (nvp = nvlist_next_nvpair(cbarg.cb_onvl, NULL); nvp != NULL; + nvp = nvlist_next_nvpair(cbarg.cb_onvl, nvp)) { + + if (strcmp(nvpair_name(nvp), ifname) != 0) + continue; + + if ((err = nvpair_value_nvlist(nvp, &nvl)) != 0 || + (err = nvlist_dup(nvl, if_info_nvl, NV_UNIQUE_NAME)) != 0) + *if_info_nvl = NULL; + + break; + } + + done: + nvlist_free(cbarg.cb_onvl); + + return (err); }