Print this page
Commit IPMP changes

*** 18,31 **** --- 18,33 ---- * * CDDL HEADER END */ /* * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2014 Nexenta Systems, Inc. All rights reserved. */ #include <errno.h> #include <sys/sockio.h> + #include <sys/list.h> #include <string.h> #include <assert.h> #include <unistd.h> #include <stropts.h> #include <strings.h>
*** 34,52 **** #include <libinetutil.h> #include <inet/ip.h> #include <limits.h> #include <zone.h> #include <ipadm_ndpd.h> #include "libipadm_impl.h" static ipadm_status_t i_ipadm_slifname_arp(char *, uint64_t, int); static ipadm_status_t i_ipadm_slifname(ipadm_handle_t, char *, char *, uint64_t, int, uint32_t); static ipadm_status_t i_ipadm_create_ipmp_peer(ipadm_handle_t, char *, sa_family_t); static ipadm_status_t i_ipadm_persist_if(ipadm_handle_t, const char *, ! sa_family_t); /* * Returns B_FALSE if the interface in `ifname' has at least one address that is * IFF_UP in the addresses in `ifa'. */ --- 36,70 ---- #include <libinetutil.h> #include <inet/ip.h> #include <limits.h> #include <zone.h> #include <ipadm_ndpd.h> + #include <ipmp_query.h> #include "libipadm_impl.h" static ipadm_status_t i_ipadm_slifname_arp(char *, uint64_t, int); static ipadm_status_t i_ipadm_slifname(ipadm_handle_t, char *, char *, uint64_t, int, uint32_t); static ipadm_status_t i_ipadm_create_ipmp_peer(ipadm_handle_t, char *, sa_family_t); static ipadm_status_t i_ipadm_persist_if(ipadm_handle_t, const char *, ! sa_family_t, uint32_t); ! static ipadm_status_t i_ipadm_allocate_ifinfo(ipadm_if_info_t **); ! static ipadm_status_t i_ipadm_get_db_if(ipadm_handle_t, const char *, ! nvlist_t **); ! static ipadm_status_t i_ipadm_nvl2ifinfo(nvlist_t *, ipadm_if_info_t **); ! static ipadm_status_t i_ipadm_fill_cmembers(char *, ipadm_ipmp_members_t *); ! static ipadm_status_t i_ipadm_fill_pmembers(nvlist_t *, ipadm_ipmp_members_t *); ! static ipadm_status_t i_ipadm_add_persistent_if_info(ipadm_if_info_t *, ! ipadm_if_info_t *); ! static void i_ipadm_free_ipmp_members(ipadm_ipmp_members_t *); ! static ipadm_status_t i_ipadm_persist_update_ipmp(ipadm_handle_t, const char *, ! const char *, ! ipadm_ipmp_operation_t); ! static ipadm_status_t i_ipadm_update_ipmp(ipadm_handle_t, const char *, ! const char *, uint32_t, ! ipadm_ipmp_operation_t); /* * Returns B_FALSE if the interface in `ifname' has at least one address that is * IFF_UP in the addresses in `ifa'. */
*** 120,134 **** for (ifp = *if_info; ifp != NULL; ifp = ifp->ifi_next) { if (strcmp(lifrp->lifr_name, ifp->ifi_name) == 0) break; } if (ifp == NULL) { ! ifp = calloc(1, sizeof (ipadm_if_info_t)); ! if (ifp == NULL) { ! status = ipadm_errno2status(errno); ! goto fail; ! } (void) strlcpy(ifp->ifi_name, lifrp->lifr_name, sizeof (ifp->ifi_name)); /* Update the `ifi_next' pointer for this new node */ if (*if_info == NULL) *if_info = ifp; --- 138,151 ---- for (ifp = *if_info; ifp != NULL; ifp = ifp->ifi_next) { if (strcmp(lifrp->lifr_name, ifp->ifi_name) == 0) break; } if (ifp == NULL) { ! if ((status = ! i_ipadm_allocate_ifinfo(&ifp)) != IPADM_SUCCESS) ! break; ! (void) strlcpy(ifp->ifi_name, lifrp->lifr_name, sizeof (ifp->ifi_name)); /* Update the `ifi_next' pointer for this new node */ if (*if_info == NULL) *if_info = ifp;
*** 145,164 **** lifrp->lifr_name, sizeof (lifrl.lifr_name)); s = (lifrp->lifr_addr.ss_family == AF_INET) ? iph->iph_sock : iph->iph_sock6; if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0) continue; if (lifrl.lifr_flags & IFF_BROADCAST) ifp->ifi_cflags |= IFIF_BROADCAST; if (lifrl.lifr_flags & IFF_MULTICAST) ifp->ifi_cflags |= IFIF_MULTICAST; if (lifrl.lifr_flags & IFF_POINTOPOINT) ifp->ifi_cflags |= IFIF_POINTOPOINT; ! if (lifrl.lifr_flags & IFF_VIRTUAL) ifp->ifi_cflags |= IFIF_VIRTUAL; ! if (lifrl.lifr_flags & IFF_IPMP) ifp->ifi_cflags |= IFIF_IPMP; if (lifrl.lifr_flags & IFF_STANDBY) ifp->ifi_cflags |= IFIF_STANDBY; if (lifrl.lifr_flags & IFF_INACTIVE) ifp->ifi_cflags |= IFIF_INACTIVE; if (lifrl.lifr_flags & IFF_VRRP) --- 162,189 ---- lifrp->lifr_name, sizeof (lifrl.lifr_name)); s = (lifrp->lifr_addr.ss_family == AF_INET) ? iph->iph_sock : iph->iph_sock6; if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0) continue; + + /* a regular interface by default */ + ifp->ifi_class = IPADM_IF_CLASS_REGULAR; + if (lifrl.lifr_flags & IFF_BROADCAST) ifp->ifi_cflags |= IFIF_BROADCAST; if (lifrl.lifr_flags & IFF_MULTICAST) ifp->ifi_cflags |= IFIF_MULTICAST; if (lifrl.lifr_flags & IFF_POINTOPOINT) ifp->ifi_cflags |= IFIF_POINTOPOINT; ! if (lifrl.lifr_flags & IFF_VIRTUAL) { ifp->ifi_cflags |= IFIF_VIRTUAL; ! ifp->ifi_class = IPADM_IF_CLASS_VIRTUAL; ! } ! if (lifrl.lifr_flags & IFF_IPMP) { ifp->ifi_cflags |= IFIF_IPMP; + ifp->ifi_class = IPADM_IF_CLASS_IPMP; + } if (lifrl.lifr_flags & IFF_STANDBY) ifp->ifi_cflags |= IFIF_STANDBY; if (lifrl.lifr_flags & IFF_INACTIVE) ifp->ifi_cflags |= IFIF_INACTIVE; if (lifrl.lifr_flags & IFF_VRRP)
*** 169,185 **** ifp->ifi_cflags |= IFIF_IPV4; if (lifrl.lifr_flags & IFF_IPV6) ifp->ifi_cflags |= IFIF_IPV6; if (lifrl.lifr_flags & IFF_L3PROTECT) ifp->ifi_cflags |= IFIF_L3PROTECT; } free(buf); ! return (IPADM_SUCCESS); ! fail: ! free(buf); ipadm_free_if_info(*if_info); *if_info = NULL; return (status); } /* * Returns the interface information for `ifname' in `if_info' from persistent --- 194,223 ---- ifp->ifi_cflags |= IFIF_IPV4; if (lifrl.lifr_flags & IFF_IPV6) ifp->ifi_cflags |= IFIF_IPV6; if (lifrl.lifr_flags & IFF_L3PROTECT) ifp->ifi_cflags |= IFIF_L3PROTECT; + + /* Retrive active IPMP members */ + if (ifp->ifi_class == IPADM_IF_CLASS_IPMP) { + if (ioctl(s, SIOCGLIFGROUPNAME, + (caddr_t)&lifrl) < 0) { + status = ipadm_errno2status(errno); + break; } + + if ((status = i_ipadm_fill_cmembers( + lifrl.lifr_groupname, + &ifp->ifi_ipmp_cmembers)) != IPADM_SUCCESS) + break; + } + } free(buf); ! if (status != IPADM_SUCCESS) { ipadm_free_if_info(*if_info); *if_info = NULL; + } return (status); } /* * Returns the interface information for `ifname' in `if_info' from persistent
*** 189,239 **** static ipadm_status_t i_ipadm_persist_if_info(ipadm_handle_t iph, const char *ifname, ipadm_if_info_t **if_info) { ipadm_status_t status = IPADM_SUCCESS; ! ipmgmt_getif_arg_t getif; ! ipmgmt_getif_rval_t *rvalp; ! ipadm_if_info_t *ifp, *curr, *prev = NULL; ! int i = 0, err = 0; - bzero(&getif, sizeof (getif)); - if (ifname != NULL) - (void) strlcpy(getif.ia_ifname, ifname, LIFNAMSIZ); - getif.ia_cmd = IPMGMT_CMD_GETIF; - *if_info = NULL; ! if ((rvalp = malloc(sizeof (ipmgmt_getif_rval_t))) == NULL) return (ipadm_errno2status(errno)); ! err = ipadm_door_call(iph, &getif, sizeof (getif), (void **)&rvalp, ! sizeof (*rvalp), B_TRUE); ! if (err == ENOENT) { ! free(rvalp); ! if (ifname != NULL) ! return (ipadm_errno2status(err)); return (IPADM_SUCCESS); ! } else if (err != 0) { ! free(rvalp); ! return (ipadm_errno2status(err)); } ! ifp = rvalp->ir_ifinfo; ! for (i = 0; i < rvalp->ir_ifcnt; i++) { ! ifp = rvalp->ir_ifinfo + i; ! if ((curr = malloc(sizeof (*curr))) == NULL) { ! status = ipadm_errno2status(errno); ! ipadm_free_if_info(prev); ! break; } ! (void) bcopy(ifp, curr, sizeof (*curr)); ! curr->ifi_next = prev; ! prev = curr; } ! *if_info = curr; ! free(rvalp); ! return (status); } /* * Collects information for `ifname' if one is specified from both * active and persistent config in `if_info'. If no `ifname' is specified, --- 227,383 ---- static ipadm_status_t i_ipadm_persist_if_info(ipadm_handle_t iph, const char *ifname, ipadm_if_info_t **if_info) { ipadm_status_t status = IPADM_SUCCESS; ! nvlist_t *ifs_info_nvl; *if_info = NULL; ! if ((status = i_ipadm_get_db_if(iph, ! ifname, &ifs_info_nvl)) != IPADM_SUCCESS) ! return (status); ! ! assert(ifs_info_nvl != NULL); ! ! return (i_ipadm_nvl2ifinfo(ifs_info_nvl, if_info)); ! } ! ! static ipadm_status_t ! i_ipadm_nvl2ifinfo(nvlist_t *ifs_info_nvl, ipadm_if_info_t **if_info) ! { ! ipadm_if_info_t *ific = NULL, *ifil = NULL; ! nvlist_t *if_info_nvl; ! nvpair_t *nvp; ! char *strval; ! ipadm_status_t status = IPADM_SUCCESS; ! uint16_t *families; ! uint_t nelem = 0; ! ! for (nvp = nvlist_next_nvpair(ifs_info_nvl, NULL); nvp != NULL; ! nvp = nvlist_next_nvpair(ifs_info_nvl, nvp)) { ! if (nvpair_value_nvlist(nvp, &if_info_nvl) != 0) ! continue; ! ! status = i_ipadm_allocate_ifinfo(&ific); ! if (status != IPADM_SUCCESS) { ! ipadm_free_if_info(*if_info); ! break; ! } ! if (nvlist_lookup_string(if_info_nvl, IPADM_NVP_IFNAME, ! &strval) != 0) { ! ipadm_free_if_info(ific); ! ific = NULL; ! continue; ! } ! (void) strlcpy(ific->ifi_name, strval, ! sizeof (ific->ifi_name)); ! ! if (nvlist_lookup_uint16_array(if_info_nvl, ! IPADM_NVP_FAMILIES, &families, &nelem) == 0) { ! ! while (nelem--) { ! if (families[nelem] == AF_INET) ! ific->ifi_pflags |= IFIF_IPV4; ! else if (families[nelem] == AF_INET6) ! ific->ifi_pflags |= IFIF_IPV6; ! } ! } else { ! ipadm_free_if_info(ific); ! ific = NULL; ! continue; ! } ! if (nvlist_lookup_string(if_info_nvl, ! IPADM_NVP_IFCLASS, &strval) == 0) ! ific->ifi_class = atoi(strval); ! else ! ific->ifi_class = IPADM_IF_CLASS_REGULAR; ! ! if (ific->ifi_class == IPADM_IF_CLASS_IPMP) ! i_ipadm_fill_pmembers(if_info_nvl, ! &ific->ifi_ipmp_pmembers); ! ! if (*if_info == NULL) ! *if_info = ific; ! else ! ifil->ifi_next = ific; ! ifil = ific; ! } ! ! nvlist_free(ifs_info_nvl); ! return (status); ! } ! ! /* ! * Fill the ipadm_if_info_t->ifi_ipmp_pmembers by info from ! * ipadm DB ! */ ! static ipadm_status_t ! i_ipadm_fill_pmembers(nvlist_t *if_info_nvl, ipadm_ipmp_members_t *pmembers) ! { ! uint_t nelem = 0; ! char **members; ! ipadm_ipmp_member_t *ipmp_member; ! ! if (nvlist_lookup_string_array(if_info_nvl, IPADM_NVP_MIFNAMES, ! &members, &nelem) != 0) ! return (IPADM_SUCCESS); ! ! while (nelem--) { ! if ((ipmp_member = calloc(1, ! sizeof (ipadm_ipmp_member_t))) == NULL) return (ipadm_errno2status(errno)); ! ! (void) strlcpy(ipmp_member->if_name, members[nelem], ! sizeof (ipmp_member->if_name)); ! list_insert_tail(pmembers, ipmp_member); ! } return (IPADM_SUCCESS); ! } ! ! /* ! * Fill the ipadm_if_info_t->ifi_ipmp_cmembers by info from ! * kernel (libipmp is used to retrive the required info) ! */ ! static ipadm_status_t ! i_ipadm_fill_cmembers(char *gropname, ipadm_ipmp_members_t *cmembers) ! { ! ipmp_handle_t ipmp_handle; ! ipmp_groupinfo_t *grinfo; ! ipmp_iflist_t *iflistp; ! ipadm_ipmp_member_t *ipmp_member; ! ipadm_status_t ipadm_status = IPADM_SUCCESS; ! int ipmp_status; ! uint_t i; ! ! if ((ipmp_status = ipmp_open(&ipmp_handle)) != IPMP_SUCCESS) ! return (IPADM_FAILURE); ! ! if ((ipmp_status = ipmp_getgroupinfo(ipmp_handle, ! gropname, ! &grinfo)) != IPMP_SUCCESS) { ! ipadm_status = IPADM_FAILURE; ! goto fail; } ! iflistp = grinfo->gr_iflistp; ! for (i = 0; i < iflistp->il_nif; i++) { ! if ((ipmp_member = calloc(1, ! sizeof (ipadm_ipmp_member_t))) == NULL) { ! ipadm_status = ipadm_errno2status(errno); ! goto fail; } ! ! (void) strlcpy(ipmp_member->if_name, iflistp->il_ifs[i], ! sizeof (ipmp_member->if_name)); ! list_insert_tail(cmembers, ipmp_member); } ! ! fail: ! ipmp_freegroupinfo(grinfo); ! ipmp_close(ipmp_handle); ! return (ipadm_status); } /* * Collects information for `ifname' if one is specified from both * active and persistent config in `if_info'. If no `ifname' is specified,
*** 322,350 **** * add this interface to `aifinfo' and set it state to IFIF_DISABLED. */ for (pifp = pifinfo; pifp != NULL; pifp = pifp->ifi_next) { for (aifp = aifinfo; aifp != NULL; aifp = aifp->ifi_next) { if (strcmp(aifp->ifi_name, pifp->ifi_name) == 0) { - aifp->ifi_pflags = pifp->ifi_pflags; break; } } if (aifp == NULL) { ! aifp = malloc(sizeof (ipadm_if_info_t)); ! if (aifp == NULL) { ! status = ipadm_errno2status(errno); goto fail; ! } ! *aifp = *pifp; aifp->ifi_next = NULL; aifp->ifi_state = IFIS_DISABLED; if (last != NULL) last->ifi_next = aifp; else aifinfo = aifp; last = aifp; } } *if_info = aifinfo; ipadm_free_if_info(pifinfo); return (IPADM_SUCCESS); fail: --- 466,499 ---- * add this interface to `aifinfo' and set it state to IFIF_DISABLED. */ for (pifp = pifinfo; pifp != NULL; pifp = pifp->ifi_next) { for (aifp = aifinfo; aifp != NULL; aifp = aifp->ifi_next) { if (strcmp(aifp->ifi_name, pifp->ifi_name) == 0) { break; } } + if (aifp == NULL) { ! if ((status = ! i_ipadm_allocate_ifinfo(&aifp)) != IPADM_SUCCESS) goto fail; ! ! (void) strlcpy(aifp->ifi_name, pifp->ifi_name, ! sizeof (aifp->ifi_name)); ! aifp->ifi_next = NULL; aifp->ifi_state = IFIS_DISABLED; if (last != NULL) last->ifi_next = aifp; else aifinfo = aifp; last = aifp; } + + if ((status = i_ipadm_add_persistent_if_info(aifp, + pifp)) != IPADM_SUCCESS) + goto fail; } *if_info = aifinfo; ipadm_free_if_info(pifinfo); return (IPADM_SUCCESS); fail:
*** 352,361 **** --- 501,579 ---- ipadm_free_if_info(aifinfo); ipadm_free_if_info(pifinfo); return (status); } + /* + * Updates active if_info by data from persistent if_info + */ + static ipadm_status_t + i_ipadm_add_persistent_if_info(ipadm_if_info_t *aifp, ipadm_if_info_t *pifp) + { + ipadm_ipmp_member_t *pp_ipmp_member, *ap_ipmp_member; + + ipadm_ipmp_members_t *apmembers = &aifp->ifi_ipmp_pmembers; + ipadm_ipmp_members_t *ppmembers = &pifp->ifi_ipmp_pmembers; + + aifp->ifi_pflags = pifp->ifi_pflags; + aifp->ifi_class = pifp->ifi_class; + + for (pp_ipmp_member = list_head(ppmembers); pp_ipmp_member; + pp_ipmp_member = list_next(ppmembers, pp_ipmp_member)) { + if ((ap_ipmp_member = calloc(1, + sizeof (ipadm_ipmp_member_t))) == NULL) + return (ipadm_errno2status(errno)); + + (void) strlcpy(ap_ipmp_member->if_name, + pp_ipmp_member->if_name, + sizeof (ap_ipmp_member->if_name)); + + list_insert_tail(apmembers, ap_ipmp_member); + } + return (IPADM_SUCCESS); + } + + static ipadm_status_t + i_ipadm_allocate_ifinfo(ipadm_if_info_t **if_info) + { + *if_info = calloc(1, sizeof (ipadm_if_info_t)); + if (*if_info == NULL) + return (ipadm_errno2status(errno)); + + /* List of active (current) members */ + list_create(&((*if_info)->ifi_ipmp_cmembers), + sizeof (ipadm_ipmp_member_t), + offsetof(ipadm_ipmp_member_t, node)); + + /* List of persistent members */ + list_create(&((*if_info)->ifi_ipmp_pmembers), + sizeof (ipadm_ipmp_member_t), + offsetof(ipadm_ipmp_member_t, node)); + + return (IPADM_SUCCESS); + } + + /* + * Reads all the interface lines from the persistent DB into the nvlist `onvl', + * when `ifname' is NULL. + * If an `ifname' is specified, then the interface line corresponding to + * that name will be returned. + */ + static ipadm_status_t + i_ipadm_get_db_if(ipadm_handle_t iph, const char *ifname, nvlist_t **onvl) + { + ipmgmt_getif_arg_t garg; + + /* Populate the door_call argument structure */ + bzero(&garg, sizeof (garg)); + garg.ia_cmd = IPMGMT_CMD_GETIF; + if (ifname != NULL) + (void) strlcpy(garg.ia_ifname, ifname, sizeof (garg.ia_ifname)); + + return (i_ipadm_call_ipmgmtd(iph, (void *) &garg, sizeof (garg), onvl)); + } + int i_ipadm_get_lnum(const char *ifname) { char *num = strrchr(ifname, IPADM_LOGICAL_SEP);
*** 391,401 **** if (status == IPADM_SUCCESS) { *exists = ((af == AF_INET && (ifinfo->ifi_pflags & IFIF_IPV4)) || (af == AF_INET6 && (ifinfo->ifi_pflags & IFIF_IPV6))); ! free(ifinfo); } else if (status == IPADM_NOTFOUND) { status = IPADM_SUCCESS; *exists = B_FALSE; } return (status); --- 609,619 ---- if (status == IPADM_SUCCESS) { *exists = ((af == AF_INET && (ifinfo->ifi_pflags & IFIF_IPV4)) || (af == AF_INET6 && (ifinfo->ifi_pflags & IFIF_IPV6))); ! ipadm_free_if_info(ifinfo); } else if (status == IPADM_NOTFOUND) { status = IPADM_SUCCESS; *exists = B_FALSE; } return (status);
*** 730,740 **** bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr)); lifr.lifr_addr.ss_family = af; if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0) return (ipadm_errno2status(errno)); if (is_persistent) { ! status = i_ipadm_persist_if(iph, ifname, af); if (status != IPADM_SUCCESS) { (void) i_ipadm_delete_if(iph, ifname, af, IPADM_OPT_ACTIVE); } } --- 948,959 ---- bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr)); lifr.lifr_addr.ss_family = af; if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0) return (ipadm_errno2status(errno)); if (is_persistent) { ! status = i_ipadm_persist_if(iph, ! ifname, af, ipadm_flags); if (status != IPADM_SUCCESS) { (void) i_ipadm_delete_if(iph, ifname, af, IPADM_OPT_ACTIVE); } }
*** 911,921 **** /* * If IPADM_OPT_PERSIST was set in flags, store the * interface in persistent DB. */ if (is_persistent) { ! status = i_ipadm_persist_if(iph, newif, af); if (status != IPADM_SUCCESS) { (void) i_ipadm_delete_if(iph, newif, af, IPADM_OPT_ACTIVE); } } --- 1130,1141 ---- /* * If IPADM_OPT_PERSIST was set in flags, store the * interface in persistent DB. */ if (is_persistent) { ! status = i_ipadm_persist_if(iph, ! newif, af, ipadm_flags); if (status != IPADM_SUCCESS) { (void) i_ipadm_delete_if(iph, newif, af, IPADM_OPT_ACTIVE); } }
*** 1144,1160 **** /* * Saves the given interface name `ifname' with address family `af' in * persistent DB. */ static ipadm_status_t ! i_ipadm_persist_if(ipadm_handle_t iph, const char *ifname, sa_family_t af) { ipmgmt_if_arg_t ifarg; int err; (void) strlcpy(ifarg.ia_ifname, ifname, sizeof (ifarg.ia_ifname)); ifarg.ia_family = af; ifarg.ia_cmd = IPMGMT_CMD_SETIF; ifarg.ia_flags = IPMGMT_PERSIST; err = ipadm_door_call(iph, &ifarg, sizeof (ifarg), NULL, 0, B_FALSE); return (ipadm_errno2status(err)); } --- 1364,1386 ---- /* * Saves the given interface name `ifname' with address family `af' in * persistent DB. */ static ipadm_status_t ! i_ipadm_persist_if(ipadm_handle_t iph, ! const char *ifname, sa_family_t af, uint32_t ipadm_flags) { ipmgmt_if_arg_t ifarg; int err; (void) strlcpy(ifarg.ia_ifname, ifname, sizeof (ifarg.ia_ifname)); ifarg.ia_family = af; + if (ipadm_flags & IPADM_OPT_IPMP) { + ifarg.ia_ifclass = IPADM_IF_CLASS_IPMP; + } else { + ifarg.ia_ifclass = IPADM_IF_CLASS_REGULAR; + } ifarg.ia_cmd = IPMGMT_CMD_SETIF; ifarg.ia_flags = IPMGMT_PERSIST; err = ipadm_door_call(iph, &ifarg, sizeof (ifarg), NULL, 0, B_FALSE); return (ipadm_errno2status(err)); }
*** 1261,1270 **** --- 1487,1497 ---- * or the persistent configuration. */ if (ipadm_if_enabled(iph, ifname, af)) return (IPADM_IF_EXISTS); + #if 0 if (!(iph->iph_flags & IPH_LEGACY)) { status = i_ipadm_if_pexists(iph, ifname, af, &p_exists); if (status != IPADM_SUCCESS) return (status); other_af = (af == AF_INET ? AF_INET6 : AF_INET);
*** 1273,1283 **** return (IPADM_OP_DISABLE_OBJ); else ipadm_flags &= ~IPADM_OPT_PERSIST; } } ! return (i_ipadm_plumb_if(iph, ifname, af, ipadm_flags)); } /* * Plumbs an interface. Creates both IPv4 and IPv6 interfaces by --- 1500,1510 ---- return (IPADM_OP_DISABLE_OBJ); else ipadm_flags &= ~IPADM_OPT_PERSIST; } } ! #endif return (i_ipadm_plumb_if(iph, ifname, af, ipadm_flags)); } /* * Plumbs an interface. Creates both IPv4 and IPv6 interfaces by
*** 1343,1353 **** --- 1570,1709 ---- } return (IPADM_SUCCESS); } + ipadm_status_t + ipadm_add_ipmp_member(ipadm_handle_t iph, const char *gifname, + const char *mifname, uint32_t flags) + { + return (i_ipadm_update_ipmp(iph, gifname, mifname, + flags, IPADM_ADD_IPMP_MEMBER)); + } + + ipadm_status_t + ipadm_remove_ipmp_member(ipadm_handle_t iph, const char *gifname, + const char *mifname, uint32_t flags) + { + return (i_ipadm_update_ipmp(iph, gifname, mifname, + flags, IPADM_REMOVE_IPMP_MEMBER)); + } + /* + * Update IPMP configuration according to requested operation, + * that can be + * + * IPADM_ADD_IPMP_MEMBER + * + * IPADM_REMOVE_IPMP_MEMBER + * + * At first it update the active config and if IPADM_OPT_PERSIST is set, + * then we also update persistent ipadm DB + */ + static ipadm_status_t + i_ipadm_update_ipmp(ipadm_handle_t iph, + const char *gifname, const char *mifname, + uint32_t flags, ipadm_ipmp_operation_t operation) + { + ipadm_status_t status; + char group_name1[LIFGRNAMSIZ]; + char group_name2[LIFGRNAMSIZ]; + + /* Check for the required authorization */ + if (!ipadm_check_auth()) + return (IPADM_EAUTH); + + if (!(flags & IPADM_OPT_ACTIVE) || + gifname == NULL || mifname == NULL) + return (IPADM_INVALID_ARG); + + if (!ipadm_if_enabled(iph, gifname, AF_UNSPEC) || + !ipadm_if_enabled(iph, mifname, AF_UNSPEC)) + return (IPADM_OP_DISABLE_OBJ); + + #if 1 + if (!i_ipadm_is_ipmp(iph, gifname)) { + return (IPADM_INVALID_ARG); + } + #endif + if (operation == IPADM_ADD_IPMP_MEMBER && + i_ipadm_is_under_ipmp(iph, mifname)) + return (IPADM_IF_INUSE); + + if ((status = i_ipadm_get_groupname_active(iph, gifname, + group_name2, LIFGRNAMSIZ)) != IPADM_SUCCESS) + return (status); + + if (operation == IPADM_REMOVE_IPMP_MEMBER) { + if ((status = i_ipadm_get_groupname_active(iph, mifname, + group_name1, LIFGRNAMSIZ)) != IPADM_SUCCESS) + return (status); + + /* FIXME: Need to return something another */ + if (group_name1[0] == '\0') + return (IPADM_INVALID_ARG); + + /* FIXME: Need to return something another */ + if (strcmp(group_name1, group_name2) != 0) + return (IPADM_INVALID_ARG); + + group_name2[0] = '\0'; + } + + if ((status = i_ipadm_set_groupname_active(iph, mifname, + group_name2)) != IPADM_SUCCESS) { + return (status); + } + if (flags & IPADM_OPT_PERSIST) { + if ((status = i_ipadm_persist_update_ipmp(iph, gifname, + mifname, operation)) != IPADM_SUCCESS) { + /* Need to revert the active configuration */ + if (operation == IPADM_ADD_IPMP_MEMBER) { + group_name2[0] = '\0'; + (void) i_ipadm_set_groupname_active(iph, + mifname, group_name2); + } + } + } + + return (status); + } + + /* + * Call the ipmgmtd to update the IPMP configuration in ipadm DB + * after this call the DB will know that mifname is under gifname and + * gifname has a member, which name is mifname + */ + static ipadm_status_t + i_ipadm_persist_update_ipmp(ipadm_handle_t iph, const char *gifname, + const char *mifname, ipadm_ipmp_operation_t operation) + { + ipmgmt_ipmp_update_arg_t args; + int err; + + assert(operation == IPADM_ADD_IPMP_MEMBER || + operation == IPADM_REMOVE_IPMP_MEMBER); + + bzero(&args, sizeof (ipmgmt_ipmp_update_arg_t)); + + args.ia_cmd = IPMGMT_CMD_IPMP_UPDATE; + + (void) strlcpy(args.ia_gifname, gifname, sizeof (args.ia_gifname)); + (void) strlcpy(args.ia_mifname, mifname, sizeof (args.ia_mifname)); + + if (operation == IPADM_ADD_IPMP_MEMBER) + args.ia_flags = IPMGMT_APPEND; + else + args.ia_flags = IPMGMT_REMOVE; + + args.ia_flags |= IPMGMT_PERSIST; + + err = ipadm_door_call(iph, &args, sizeof (args), NULL, 0, B_FALSE); + return (ipadm_errno2status(err)); + } + + /* * Deletes the interface in `ifname'. Removes both IPv4 and IPv6 interfaces * when `af' = AF_UNSPEC. */ ipadm_status_t ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af,
*** 1446,1459 **** --- 1802,1828 ---- { ipadm_if_info_t *ifinfo_next; for (; ifinfo != NULL; ifinfo = ifinfo_next) { ifinfo_next = ifinfo->ifi_next; + i_ipadm_free_ipmp_members(&ifinfo->ifi_ipmp_cmembers); + i_ipadm_free_ipmp_members(&ifinfo->ifi_ipmp_pmembers); free(ifinfo); } } + static void + i_ipadm_free_ipmp_members(ipadm_ipmp_members_t *ipmp_members) + { + ipadm_ipmp_member_t *ipmp_member; + + while ((ipmp_member = list_remove_head(ipmp_members)) != NULL) + free(ipmp_member); + + list_destroy(ipmp_members); + } + /* * Re-enable the interface `ifname' based on the saved configuration * for `ifname'. */ ipadm_status_t
*** 1558,1563 **** --- 1927,2009 ---- void ipadm_if_move(ipadm_handle_t iph, const char *ifname) { (void) i_ipadm_delete_ifobj(iph, ifname, AF_INET, B_FALSE); (void) i_ipadm_delete_ifobj(iph, ifname, AF_INET6, B_FALSE); + } + + ipadm_status_t + i_ipadm_set_groupname_active(ipadm_handle_t iph, const char *ifname, + const char *groupname) + { + struct lifreq lifr; + + memset(&lifr, 0, sizeof (lifr)); + + (void) strlcpy(lifr.lifr_name, ifname, + sizeof (lifr.lifr_name)); + + (void) strlcpy(lifr.lifr_groupname, groupname, + sizeof (lifr.lifr_groupname)); + + if (ioctl(iph->iph_sock, SIOCSLIFGROUPNAME, (caddr_t)&lifr) < 0 && + ioctl(iph->iph_sock6, SIOCSLIFGROUPNAME, (caddr_t)&lifr) < 0) { + return (ipadm_errno2status(errno)); + } + + return (IPADM_SUCCESS); + } + + ipadm_status_t + i_ipadm_get_groupname_active(ipadm_handle_t iph, const char *ifname, + char *groupname, size_t size) + { + struct lifreq lifr; + + memset(&lifr, 0, sizeof (lifr)); + + (void) strlcpy(lifr.lifr_name, ifname, + sizeof (lifr.lifr_name)); + + if (ioctl(iph->iph_sock, SIOCGLIFGROUPNAME, (caddr_t)&lifr) < 0 && + ioctl(iph->iph_sock6, SIOCGLIFGROUPNAME, (caddr_t)&lifr) < 0) + return (ipadm_errno2status(errno)); + + (void) strlcpy(groupname, lifr.lifr_groupname, size); + + return (IPADM_SUCCESS); + } + + /* + * Returns B_TRUE if `ifname' represents an IPMP underlying interface. + */ + boolean_t + i_ipadm_is_under_ipmp(ipadm_handle_t iph, const char *ifname) + { + + char groupname[LIFGRNAMSIZ]; + + if (i_ipadm_get_groupname_active(iph, ifname, groupname, + LIFGRNAMSIZ) != IPADM_SUCCESS || + groupname[0] == '\0') + return (B_FALSE); + + if (strcmp(ifname, groupname) == 0) + return (B_FALSE); + + return (B_TRUE); + } + + /* + * Returns B_TRUE if `ifname' represents an IPMP meta-interface. + */ + boolean_t + i_ipadm_is_ipmp(ipadm_handle_t iph, const char *ifname) + { + uint64_t flags; + + if (i_ipadm_get_flags(iph, ifname, AF_INET, &flags) != IPADM_SUCCESS && + i_ipadm_get_flags(iph, ifname, AF_INET6, &flags) != IPADM_SUCCESS) + return (B_FALSE); + + return ((flags & IFF_IPMP) != 0); }