Print this page
usr/src/cmd/dlmgmtd/dlmgmt_door.c

*** 23,32 **** --- 23,33 ---- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2018, Joyent Inc. * Copyright (c) 2015, 2016 by Delphix. All rights reserved. * Copyright 2019 OmniOS Community Edition (OmniOSce) Association. * Copyright 2020 RackTop Systems Inc. + * Copyright 2023 Oxide Computer Company */ /* * Copyright 2011 Nexenta Systems, Inc. All rights reserved. */
*** 84,93 **** --- 85,95 ---- #include <libdlpi.h> #include <libdllink.h> #include <libdlvlan.h> #include <libdlvnic.h> + #include <libdlaggr.h> #include <inet/tcp.h> #include <arpa/inet.h> #include <netinet/in.h> #include <net/route.h>
*** 3026,3042 **** di_prof_fini(prof); return (0); } static int remove_datalink_pool(zlog_t *zlogp, zoneid_t zoneid) { ushort_t flags; zone_iptype_t iptype; ! int i, dlnum = 0; ! datalink_id_t *dllink, *dllinks = NULL; dladm_status_t err; if (strlen(pool_name) == 0) return (0); --- 3028,3106 ---- di_prof_fini(prof); return (0); } + /* + * Retrieve the list of datalink IDs assigned to a zone. + * + * On return, *count will be updated with the total number of links and, if it + * is not NULL, **linksp will be updated to point to allocated memory + * containing the link IDs. This should be passed to free() when the caller is + * finished with it. + */ static int + fetch_zone_datalinks(zlog_t *zlogp, zoneid_t zoneid, int *countp, + datalink_id_t **linksp) + { + datalink_id_t *links = NULL; + int links_size = 0; + int num_links; + + if (linksp != NULL) + *linksp = NULL; + *countp = 0; + + num_links = 0; + if (zone_list_datalink(zoneid, &num_links, NULL) != 0) { + zerror(zlogp, B_TRUE, + "unable to determine number of network interfaces"); + return (-1); + } + + if (num_links == 0) + return (0); + + /* If linkp is NULL, the caller only wants the count. */ + if (linksp == NULL) { + *countp = num_links; + return (0); + } + + do { + datalink_id_t *p; + + links_size = num_links; + p = reallocarray(links, links_size, sizeof (datalink_id_t)); + + if (p == NULL) { + zerror(zlogp, B_TRUE, + "failed to allocate memory for zone links"); + free(links); + return (-1); + } + links = p; + + if (zone_list_datalink(zoneid, &num_links, links) != 0) { + zerror(zlogp, B_TRUE, "failed to list zone links"); + free(links); + return (-1); + } + } while (links_size < num_links); + + *countp = num_links; + *linksp = links; + + return (0); + } + + static int remove_datalink_pool(zlog_t *zlogp, zoneid_t zoneid) { ushort_t flags; zone_iptype_t iptype; ! int i; dladm_status_t err; if (strlen(pool_name) == 0) return (0);
*** 3052,3089 **** else iptype = ZS_SHARED; } if (iptype == ZS_EXCLUSIVE) { ! /* ! * Get the datalink count and for each datalink, ! * attempt to clear the pool property and clear ! * the pool_name. ! */ ! if (zone_list_datalink(zoneid, &dlnum, NULL) != 0) { ! zerror(zlogp, B_TRUE, "unable to count network " ! "interfaces"); ! return (-1); ! } ! if (dlnum == 0) ! return (0); ! ! if ((dllinks = malloc(dlnum * sizeof (datalink_id_t))) ! == NULL) { ! zerror(zlogp, B_TRUE, "memory allocation failed"); return (-1); - } - if (zone_list_datalink(zoneid, &dlnum, dllinks) != 0) { - zerror(zlogp, B_TRUE, "unable to list network " - "interfaces"); - return (-1); - } bzero(pool_name, sizeof (pool_name)); ! for (i = 0, dllink = dllinks; i < dlnum; i++, dllink++) { ! err = dladm_set_linkprop(dld_handle, *dllink, "pool", NULL, 0, DLADM_OPT_ACTIVE); if (err != DLADM_STATUS_OK) { zerror(zlogp, B_TRUE, "WARNING: unable to clear pool"); } --- 3116,3134 ---- else iptype = ZS_SHARED; } if (iptype == ZS_EXCLUSIVE) { ! datalink_id_t *dllinks = NULL; ! int dlnum = 0; ! if (fetch_zone_datalinks(zlogp, zoneid, &dlnum, &dllinks) != 0) return (-1); bzero(pool_name, sizeof (pool_name)); ! for (i = 0; i < dlnum; i++) { ! err = dladm_set_linkprop(dld_handle, dllinks[i], "pool", NULL, 0, DLADM_OPT_ACTIVE); if (err != DLADM_STATUS_OK) { zerror(zlogp, B_TRUE, "WARNING: unable to clear pool"); }
*** 3098,3108 **** { ushort_t flags; zone_iptype_t iptype; int i, dlnum = 0; dladm_status_t dlstatus; ! datalink_id_t *dllink, *dllinks = NULL; if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &flags, sizeof (flags)) < 0) { if (vplat_get_iptype(zlogp, &iptype) < 0) { zerror(zlogp, B_FALSE, "unable to determine ip-type"); --- 3143,3153 ---- { ushort_t flags; zone_iptype_t iptype; int i, dlnum = 0; dladm_status_t dlstatus; ! datalink_id_t *dllinks = NULL; if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &flags, sizeof (flags)) < 0) { if (vplat_get_iptype(zlogp, &iptype) < 0) { zerror(zlogp, B_FALSE, "unable to determine ip-type");
*** 3117,3174 **** if (iptype != ZS_EXCLUSIVE) return (0); /* ! * Get the datalink count and for each datalink, ! * attempt to clear the pool property and clear ! * the pool_name. */ - if (zone_list_datalink(zoneid, &dlnum, NULL) != 0) { - zerror(zlogp, B_TRUE, "unable to count network interfaces"); - return (-1); - } ! if (dlnum == 0) ! return (0); ! ! if ((dllinks = malloc(dlnum * sizeof (datalink_id_t))) == NULL) { ! zerror(zlogp, B_TRUE, "memory allocation failed"); return (-1); - } - if (zone_list_datalink(zoneid, &dlnum, dllinks) != 0) { - zerror(zlogp, B_TRUE, "unable to list network interfaces"); - free(dllinks); - return (-1); - } ! for (i = 0, dllink = dllinks; i < dlnum; i++, dllink++) { char dlerr[DLADM_STRSIZE]; ! dlstatus = dladm_set_linkprop(dld_handle, *dllink, "protection", NULL, 0, DLADM_OPT_ACTIVE); if (dlstatus == DLADM_STATUS_NOTFOUND) { /* datalink does not belong to the GZ */ continue; } ! if (dlstatus != DLADM_STATUS_OK) zerror(zlogp, B_FALSE, ! "clear 'protection' link property: %s", ! dladm_status2str(dlstatus, dlerr)); ! dlstatus = dladm_set_linkprop(dld_handle, *dllink, "allowed-ips", NULL, 0, DLADM_OPT_ACTIVE); ! if (dlstatus != DLADM_STATUS_OK) zerror(zlogp, B_FALSE, ! "clear 'allowed-ips' link property: %s", ! dladm_status2str(dlstatus, dlerr)); } free(dllinks); return (0); } static int tcp_abort_conn(zlog_t *zlogp, zoneid_t zoneid, const struct sockaddr_storage *local, const struct sockaddr_storage *remote) { int fd; struct strioctl ioc; --- 3162,3279 ---- if (iptype != ZS_EXCLUSIVE) return (0); /* ! * Get the datalink count and for each datalink, attempt to clear the ! * protection and allowed_ips properties. */ ! if (fetch_zone_datalinks(zlogp, zoneid, &dlnum, &dllinks) != 0) return (-1); ! for (i = 0; i < dlnum; i++) { char dlerr[DLADM_STRSIZE]; ! dlstatus = dladm_set_linkprop(dld_handle, dllinks[i], "protection", NULL, 0, DLADM_OPT_ACTIVE); if (dlstatus == DLADM_STATUS_NOTFOUND) { /* datalink does not belong to the GZ */ continue; } ! if (dlstatus != DLADM_STATUS_OK) { zerror(zlogp, B_FALSE, ! "clear link %d 'protection' link property: %s", ! dllinks[i], dladm_status2str(dlstatus, dlerr)); ! } ! dlstatus = dladm_set_linkprop(dld_handle, dllinks[i], "allowed-ips", NULL, 0, DLADM_OPT_ACTIVE); ! if (dlstatus != DLADM_STATUS_OK) { zerror(zlogp, B_FALSE, ! "clear link %d 'allowed-ips' link property: %s", ! dllinks[i], dladm_status2str(dlstatus, dlerr)); } + } free(dllinks); return (0); } static int + unconfigure_exclusive_network_interfaces(zlog_t *zlogp, zoneid_t zoneid) + { + datalink_id_t *dllinks; + int dlnum = 0; + uint_t i; + + /* + * The kernel shutdown callback for the dls module should have removed + * all datalinks from this zone. If any remain, then there's a + * problem. + */ + + if (fetch_zone_datalinks(zlogp, zoneid, &dlnum, &dllinks) != 0) + return (-1); + + if (dlnum == 0) + return (0); + + /* + * There are some datalinks left in the zone. The most likely cause of + * this is that the datalink-management daemon (dlmgmtd) was not + * running when the zone was shut down. That prevented the kernel from + * doing the required upcall to move the links back to the GZ. To + * attempt recovery, do that now. + */ + + for (i = 0; i < dlnum; i++) { + char dlerr[DLADM_STRSIZE]; + dladm_status_t status; + uint32_t link_flags; + datalink_id_t link = dllinks[i]; + char *prop_vals[] = { GLOBAL_ZONENAME }; + + status = dladm_datalink_id2info(dld_handle, link, + &link_flags, NULL, NULL, NULL, 0); + + if (status != DLADM_STATUS_OK) { + zerror(zlogp, B_FALSE, + "failed to get link info for %u: %s", + link, dladm_status2str(status, dlerr)); + continue; + } + + if (link_flags & DLADM_OPT_TRANSIENT) + continue; + + status = dladm_set_linkprop(dld_handle, link, "zone", + prop_vals, 1, DLADM_OPT_ACTIVE); + + if (status != DLADM_STATUS_OK) { + zerror(zlogp, B_FALSE, + "failed to move link %u to GZ: %s", + link, dladm_status2str(status, dlerr)); + } + } + + free(dllinks); + + /* Check again and log a message if links remain */ + + if (fetch_zone_datalinks(zlogp, zoneid, &dlnum, NULL) != 0) + return (-1); + + if (dlnum == 0) + return (0); + + zerror(zlogp, B_FALSE, "%d datalink(s) remain in zone after shutdown", + dlnum); + + return (-1); + } + + static int tcp_abort_conn(zlog_t *zlogp, zoneid_t zoneid, const struct sockaddr_storage *local, const struct sockaddr_storage *remote) { int fd; struct strioctl ioc;
*** 5213,5292 **** return (0); } } /* ! * Delete all transient VNICs belonging to this zone. A transient VNIC * is one that is created and destroyed along with the lifetime of the ! * zone. Non-transient VNICs, ones that are assigned from the GZ to a * NGZ, are reassigned to the GZ in zone_shutdown() via the * zone-specific data (zsd) callbacks. */ static int ! delete_transient_vnics(zlog_t *zlogp, zoneid_t zoneid) { ! dladm_status_t status; ! int num_links = 0; ! datalink_id_t *links, link; ! uint32_t link_flags; ! datalink_class_t link_class; ! char link_name[MAXLINKNAMELEN]; ! if (zone_list_datalink(zoneid, &num_links, NULL) != 0) { ! zerror(zlogp, B_TRUE, "unable to determine " ! "number of network interfaces"); return (-1); - } ! if (num_links == 0) return (0); ! links = malloc(num_links * sizeof (datalink_id_t)); ! ! if (links == NULL) { ! zerror(zlogp, B_TRUE, "failed to delete " ! "network interfaces because of alloc fail"); ! return (-1); ! } ! ! if (zone_list_datalink(zoneid, &num_links, links) != 0) { ! zerror(zlogp, B_TRUE, "failed to delete " ! "network interfaces because of failure " ! "to list them"); ! return (-1); ! } ! ! for (int i = 0; i < num_links; i++) { char dlerr[DLADM_STRSIZE]; ! link = links[i]; status = dladm_datalink_id2info(dld_handle, link, &link_flags, &link_class, NULL, link_name, sizeof (link_name)); if (status != DLADM_STATUS_OK) { ! zerror(zlogp, B_FALSE, "failed to " ! "delete network interface (%u)" ! "due to failure to get link info: %s", ! link, ! dladm_status2str(status, dlerr)); ! return (-1); } ! if (link_flags & DLADM_OPT_TRANSIENT) { ! assert(link_class & DATALINK_CLASS_VNIC); status = dladm_vnic_delete(dld_handle, link, DLADM_OPT_ACTIVE); if (status != DLADM_STATUS_OK) { ! zerror(zlogp, B_TRUE, "failed to delete link " ! "with id %d: %s", link, ! dladm_status2str(status, dlerr)); ! return (-1); } } - } return (0); } int vplat_teardown(zlog_t *zlogp, boolean_t unmount_cmd, boolean_t rebooting, --- 5318,5396 ---- return (0); } } /* ! * Delete all transient links belonging to this zone. A transient link * is one that is created and destroyed along with the lifetime of the ! * zone. Non-transient links, ones that are assigned from the GZ to a * NGZ, are reassigned to the GZ in zone_shutdown() via the * zone-specific data (zsd) callbacks. */ static int ! delete_transient_links(zlog_t *zlogp, zoneid_t zoneid) { ! datalink_id_t *dllinks = NULL; ! int dlnum = 0; ! uint_t i; ! if (fetch_zone_datalinks(zlogp, zoneid, &dlnum, &dllinks) != 0) return (-1); ! if (dlnum == 0) return (0); ! for (i = 0; i < dlnum; i++) { ! char link_name[MAXLINKNAMELEN]; char dlerr[DLADM_STRSIZE]; ! datalink_id_t link = dllinks[i]; ! datalink_class_t link_class; ! dladm_status_t status; ! uint32_t link_flags; status = dladm_datalink_id2info(dld_handle, link, &link_flags, &link_class, NULL, link_name, sizeof (link_name)); if (status != DLADM_STATUS_OK) { ! zerror(zlogp, B_FALSE, ! "failed to get link info for %u: %s", ! link, dladm_status2str(status, dlerr)); ! continue; } ! if (!(link_flags & DLADM_OPT_TRANSIENT)) ! continue; ! ! switch (link_class) { ! case DATALINK_CLASS_VNIC: ! case DATALINK_CLASS_ETHERSTUB: status = dladm_vnic_delete(dld_handle, link, DLADM_OPT_ACTIVE); + break; + case DATALINK_CLASS_VLAN: + status = dladm_vlan_delete(dld_handle, link, + DLADM_OPT_ACTIVE); + break; + case DATALINK_CLASS_AGGR: + status = dladm_aggr_delete(dld_handle, link, + DLADM_OPT_ACTIVE); + break; + default: + zerror(zlogp, B_FALSE, + "unhandled class for transient link %s (%u)", + link_name, link); + continue; + } if (status != DLADM_STATUS_OK) { ! zerror(zlogp, B_TRUE, ! "failed to delete transient link %s (%u): %s", ! link_name, link, dladm_status2str(status, dlerr)); } } + free(dllinks); return (0); } int vplat_teardown(zlog_t *zlogp, boolean_t unmount_cmd, boolean_t rebooting,
*** 5326,5341 **** if (unmount_cmd) (void) lu_root_teardown(zlogp); goto error; } ! if (remove_datalink_pool(zlogp, zoneid) != 0) ! zerror(zlogp, B_FALSE, "unable clear datalink pool property"); ! if (remove_datalink_protect(zlogp, zoneid) != 0) zerror(zlogp, B_FALSE, ! "unable clear datalink protect property"); /* * The datalinks assigned to the zone will be removed from the NGZ as * part of zone_shutdown() so that we need to remove protect/pool etc. * before zone_shutdown(). Even if the shutdown itself fails, the zone --- 5430,5448 ---- if (unmount_cmd) (void) lu_root_teardown(zlogp); goto error; } ! if (remove_datalink_pool(zlogp, zoneid) != 0) { ! zerror(zlogp, B_FALSE, ! "unable to clear datalink pool property"); ! } ! if (remove_datalink_protect(zlogp, zoneid) != 0) { zerror(zlogp, B_FALSE, ! "unable to clear datalink protect property"); ! } /* * The datalinks assigned to the zone will be removed from the NGZ as * part of zone_shutdown() so that we need to remove protect/pool etc. * before zone_shutdown(). Even if the shutdown itself fails, the zone
*** 5397,5411 **** "network interfaces in zone"); goto error; } break; case ZS_EXCLUSIVE: ! if (delete_transient_vnics(zlogp, zoneid) != 0) { zerror(zlogp, B_FALSE, "unable to delete " ! "transient vnics in zone"); goto error; } status = dladm_zone_halt(dld_handle, zoneid); if (status != DLADM_STATUS_OK) { zerror(zlogp, B_FALSE, "unable to notify " "dlmgmtd of zone halt: %s", --- 5504,5524 ---- "network interfaces in zone"); goto error; } break; case ZS_EXCLUSIVE: ! if (delete_transient_links(zlogp, zoneid) != 0) { zerror(zlogp, B_FALSE, "unable to delete " ! "transient links in zone"); goto error; } + if (unconfigure_exclusive_network_interfaces(zlogp, + zoneid) != 0) { + zerror(zlogp, B_FALSE, "unable to unconfigure " + "network interfaces in zone"); + goto error; + } status = dladm_zone_halt(dld_handle, zoneid); if (status != DLADM_STATUS_OK) { zerror(zlogp, B_FALSE, "unable to notify " "dlmgmtd of zone halt: %s",