diff options
Diffstat (limited to 'usr/src/lib/libdladm/common/libdloverlay.c')
-rw-r--r-- | usr/src/lib/libdladm/common/libdloverlay.c | 557 |
1 files changed, 490 insertions, 67 deletions
diff --git a/usr/src/lib/libdladm/common/libdloverlay.c b/usr/src/lib/libdladm/common/libdloverlay.c index ecb604fde9..3f92957bcf 100644 --- a/usr/src/lib/libdladm/common/libdloverlay.c +++ b/usr/src/lib/libdladm/common/libdloverlay.c @@ -11,6 +11,7 @@ /* * Copyright (c) 2015 Joyent, Inc. + * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. */ #include <libdladm_impl.h> @@ -25,12 +26,84 @@ #include <netinet/in.h> #include <arpa/inet.h> #include <limits.h> +#include <libscf.h> #include <libvarpd_client.h> #define VARPD_PROPERTY_NAME "varpd/id" +#define VARPD_SERVICE "network/varpd:default" static const char *dladm_overlay_doorpath = "/var/run/varpd/varpd.door"; +static boolean_t +varpd_svc_isonline(void) +{ + boolean_t isonline = B_FALSE; + char *s; + + if ((s = smf_get_state(VARPD_SERVICE)) != NULL) { + if (strcmp(s, SCF_STATE_STRING_ONLINE) == 0) + isonline = B_TRUE; + free(s); + } + + return (isonline); +} + +#define MAX_WAIT_TIME 15 + +static dladm_status_t +varpd_enable_service(void) +{ + uint_t i; + + if (varpd_svc_isonline()) + return (DLADM_STATUS_OK); + + if (smf_enable_instance(VARPD_SERVICE, 0) == -1) { + if (scf_error() == SCF_ERROR_PERMISSION_DENIED) + return (DLADM_STATUS_DENIED); + return (DLADM_STATUS_NOTFOUND); + } + + /* + * Wait up to MAX_WAIT_TIME seconds for the service + */ + for (i = 0; i < MAX_WAIT_TIME; i++) { + if (varpd_svc_isonline()) + return (DLADM_STATUS_OK); + (void) sleep(1); + } + return (DLADM_STATUS_FAILED); +} + +static int +dladm_overlay_count_cb(dladm_handle_t handle, datalink_id_t linkid, void *arg) +{ + (*(uint32_t *)arg)++; + return (DLADM_WALK_CONTINUE); +} + +/* + * Disable the varpd service if there are no overlays left. + */ +static void +varpd_disable_service_when_no_overlays(dladm_handle_t handle) +{ + uint32_t cnt = 0; + + /* + * Get the number of the existing overlays. If there are no overlays + * left, disable the service. + */ + + (void) dladm_walk_datalink_id(dladm_overlay_count_cb, handle, + &cnt, DATALINK_CLASS_OVERLAY, DATALINK_ANY_MEDIATYPE, + DLADM_OPT_ACTIVE); + + if (cnt == 0) + (void) smf_disable_instance(VARPD_SERVICE, 0); +} + typedef struct dladm_overlay_propinfo { boolean_t dop_isvarpd; union { @@ -133,10 +206,35 @@ dladm_overlay_parse_prop(overlay_prop_type_t type, void *buf, uint32_t *sizep, return (DLADM_STATUS_OK); } -/* ARGSUSED */ static dladm_status_t -dladm_overlay_varpd_setprop(dladm_handle_t handle, varpd_client_handle_t *chdl, - uint64_t inst, const char *name, char *const *valp, uint_t cnt) +i_dladm_overlay_setprop_db(dladm_handle_t handle, datalink_id_t linkid, + const char *name, char *const *valp, uint_t cnt) +{ + dladm_conf_t conf; + dladm_status_t status; + + if (linkid == DATALINK_INVALID_LINKID || + name == NULL || valp == NULL || cnt != 1) { + return (DLADM_STATUS_BADARG); + } + + status = dladm_open_conf(handle, linkid, &conf); + if (status != DLADM_STATUS_OK) + return (status); + + status = dladm_set_conf_field(handle, conf, name, DLADM_TYPE_STR, + valp[0]); + if (status == DLADM_STATUS_OK) + status = dladm_write_conf(handle, conf); + + dladm_destroy_conf(handle, conf); + return (status); +} + +static dladm_status_t +dladm_overlay_varpd_setprop(dladm_handle_t handle, + varpd_client_handle_t *chdl, uint64_t inst, datalink_id_t linkid, + const char *name, char *const *valp, uint_t cnt) { int ret; uint32_t size; @@ -165,13 +263,19 @@ dladm_overlay_varpd_setprop(dladm_handle_t handle, varpd_client_handle_t *chdl, return (status); } + status = DLADM_STATUS_OK; ret = libvarpd_c_prop_set(phdl, buf, size); libvarpd_c_prop_handle_free(phdl); + if (ret != 0) + status = dladm_errno2status(ret); - return (dladm_errno2status(ret)); + if (status != DLADM_STATUS_OK) + return (status); + + return (status); } -dladm_status_t +static dladm_status_t dladm_overlay_setprop(dladm_handle_t handle, datalink_id_t linkid, const char *name, char *const *valp, uint_t cnt) { @@ -202,16 +306,19 @@ dladm_overlay_setprop(dladm_handle_t handle, datalink_id_t linkid, prop.oip_linkid = linkid; prop.oip_id = info.oipi_id; prop.oip_name[0] = '\0'; - if ((ret = dladm_overlay_parse_prop(info.oipi_type, prop.oip_value, + if ((status = dladm_overlay_parse_prop(info.oipi_type, prop.oip_value, &prop.oip_size, valp[0])) != DLADM_STATUS_OK) - return (ret); + return (status); status = DLADM_STATUS_OK; ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_SETPROP, &prop); if (ret != 0) status = dladm_errno2status(errno); - return (ret); + if (status != DLADM_STATUS_OK) + return (status); + + return (status); } /* @@ -256,18 +363,19 @@ dladm_overlay_activate_cb(dladm_handle_t handle, datalink_id_t linkid, * datalink id. If we fail to do that, then that name will become lost to time. */ dladm_status_t -dladm_overlay_delete(dladm_handle_t handle, datalink_id_t linkid) +dladm_overlay_delete(dladm_handle_t handle, datalink_id_t linkid, + uint32_t flags) { datalink_class_t class; overlay_ioc_delete_t oid; varpd_client_handle_t *chdl; int ret; - uint32_t flags; uint64_t varpdid; - if (dladm_datalink_id2info(handle, linkid, &flags, &class, NULL, - NULL, 0) != DLADM_STATUS_OK) + if (dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, + NULL, 0) != DLADM_STATUS_OK) { return (DLADM_STATUS_BADARG); + } if (class != DATALINK_CLASS_OVERLAY) return (DLADM_STATUS_BADARG); @@ -293,7 +401,12 @@ dladm_overlay_delete(dladm_handle_t handle, datalink_id_t linkid) ret = libvarpd_c_instance_destroy(chdl, varpdid); finish: (void) libvarpd_c_destroy(chdl); - (void) dladm_destroy_datalink_id(handle, linkid, flags); + if ((flags & DLADM_OPT_PERSIST) != 0) { + (void) dladm_remove_conf(handle, linkid); + (void) dladm_destroy_datalink_id(handle, linkid, flags); + } + + (void) varpd_disable_service_when_no_overlays(handle); return (dladm_errno2status(ret)); } @@ -471,29 +584,50 @@ dladm_overlay_walk_prop(dladm_handle_t handle, datalink_id_t linkid, return (ret); } -dladm_status_t -dladm_overlay_create(dladm_handle_t handle, const char *name, - const char *encap, const char *search, uint64_t vid, - dladm_arg_list_t *props, dladm_errlist_t *errs, uint32_t flags) +static dladm_status_t +dladm_overlay_persist_config(dladm_handle_t handle, dladm_overlay_attr_t *attr) { - int ret, i; + dladm_conf_t conf; dladm_status_t status; - datalink_id_t linkid; - overlay_ioc_create_t oic; - overlay_ioc_activate_t oia; - size_t slen; - varpd_client_handle_t *vch; - uint64_t id; - status = dladm_create_datalink_id(handle, name, DATALINK_CLASS_OVERLAY, - DL_ETHER, flags, &linkid); - if (status != DLADM_STATUS_OK) + if ((status = dladm_create_conf(handle, attr->oa_name, attr->oa_linkid, + DATALINK_CLASS_OVERLAY, DL_ETHER, &conf)) != DLADM_STATUS_OK) { return (status); + } + + status = dladm_set_conf_field(handle, conf, FVNETID, + DLADM_TYPE_UINT64, &attr->oa_vid); + if (status != DLADM_STATUS_OK) + goto done; + + status = dladm_set_conf_field(handle, conf, FENCAP, + DLADM_TYPE_STR, attr->oa_encap); + if (status != DLADM_STATUS_OK) + goto done; + + status = dladm_set_conf_field(handle, conf, FSEARCH, + DLADM_TYPE_STR, attr->oa_search); + if (status != DLADM_STATUS_OK) + goto done; + + status = dladm_write_conf(handle, conf); + +done: + dladm_destroy_conf(handle, conf); + return (status); +} + +static dladm_status_t +i_dladm_overlay_create_sys(dladm_handle_t handle, dladm_overlay_attr_t *attr) +{ + overlay_ioc_create_t oic; + dladm_status_t status; + int ret; bzero(&oic, sizeof (oic)); - oic.oic_linkid = linkid; - oic.oic_vnetid = vid; - (void) strlcpy(oic.oic_encap, encap, MAXLINKNAMELEN); + oic.oic_linkid = attr->oa_linkid; + oic.oic_vnetid = attr->oa_vid; + (void) strlcpy(oic.oic_encap, attr->oa_encap, MAXLINKNAMELEN); status = DLADM_STATUS_OK; ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_CREATE, &oic); @@ -505,12 +639,22 @@ dladm_overlay_create(dladm_handle_t handle, const char *name, status = dladm_errno2status(errno); } - if (status != DLADM_STATUS_OK) { - (void) dladm_destroy_datalink_id(handle, linkid, flags); - return (status); - } + return (status); +} + +static dladm_status_t +i_dladm_overlay_commit_sys(dladm_handle_t handle, dladm_overlay_attr_t *attr, + dladm_arg_list_t *props, dladm_errlist_t *errs) +{ + overlay_ioc_activate_t oia; + varpd_client_handle_t *vch; + dladm_status_t status; + size_t slen; + uint64_t id; + int ret; + uint_t i; - slen = strlen(search); + slen = strlen(attr->oa_search); for (i = 0; props != NULL && i < props->al_count; i++) { dladm_arg_info_t *aip = &props->al_info[i]; @@ -519,33 +663,41 @@ dladm_overlay_create(dladm_handle_t handle, const char *name, * prefix '<search>/', then we don't set the property on the * overlay device and instead set it on the varpd instance. */ - if (strncmp(aip->ai_name, search, slen) == 0 && + if (strncmp(aip->ai_name, attr->oa_search, slen) == 0 && aip->ai_name[slen] == '/') continue; - status = dladm_overlay_setprop(handle, linkid, aip->ai_name, - aip->ai_val, aip->ai_count); + status = dladm_overlay_setprop(handle, attr->oa_linkid, + aip->ai_name, aip->ai_val, aip->ai_count); if (status != DLADM_STATUS_OK) { (void) dladm_errlist_append(errs, - "failed to set property %s", - aip->ai_name); - (void) dladm_overlay_delete(handle, linkid); + "failed to set property %s", aip->ai_name); return (status); } + + if (attr->oa_flags & DLADM_OPT_PERSIST) { + status = i_dladm_overlay_setprop_db(handle, + attr->oa_linkid, aip->ai_name, aip->ai_val, + aip->ai_count); + if (status != DLADM_STATUS_OK) { + (void) dladm_errlist_append(errs, + "failed to persistently set property %s", + aip->ai_name); + return (status); + } + } } if ((ret = libvarpd_c_create(&vch, dladm_overlay_doorpath)) != 0) { (void) dladm_errlist_append(errs, "failed to create libvarpd handle: %s", strerror(ret)); - (void) dladm_overlay_delete(handle, linkid); return (dladm_errno2status(ret)); } - if ((ret = libvarpd_c_instance_create(vch, linkid, search, - &id)) != 0) { + if ((ret = libvarpd_c_instance_create(vch, attr->oa_linkid, + attr->oa_search, &id)) != 0) { (void) dladm_errlist_append(errs, "failed to create varpd instance: %s", strerror(ret)); libvarpd_c_destroy(vch); - (void) dladm_overlay_delete(handle, linkid); return (dladm_errno2status(ret)); } @@ -555,39 +707,48 @@ dladm_overlay_create(dladm_handle_t handle, const char *name, /* * Skip arguments we've processed already. */ - if (strncmp(aip->ai_name, search, slen) != 0) - continue; - - if (aip->ai_name[slen] != '/') + if (strncmp(aip->ai_name, attr->oa_search, slen) != 0 || + aip->ai_name[slen] != '/') continue; - ret = dladm_overlay_varpd_setprop(handle, vch, id, aip->ai_name, - aip->ai_val, aip->ai_count); + ret = dladm_overlay_varpd_setprop(handle, vch, id, + attr->oa_linkid, aip->ai_name, aip->ai_val, aip->ai_count); if (ret != 0) { (void) dladm_errlist_append(errs, - "failed to set varpd prop: %s\n", - aip->ai_name); + "failed to set varpd prop: %s\n", aip->ai_name); (void) libvarpd_c_instance_destroy(vch, id); libvarpd_c_destroy(vch); - (void) dladm_overlay_delete(handle, linkid); return (dladm_errno2status(ret)); } + + if (attr->oa_flags & DLADM_OPT_PERSIST) { + status = i_dladm_overlay_setprop_db(handle, + attr->oa_linkid, aip->ai_name, aip->ai_val, + aip->ai_count); + if (status != DLADM_STATUS_OK) { + (void) dladm_errlist_append(errs, "failed to " + "persistently set varpd prop: %s\n", + aip->ai_name); + (void) libvarpd_c_instance_destroy(vch, id); + libvarpd_c_destroy(vch); + return (status); + } + } } if ((ret = libvarpd_c_instance_activate(vch, id)) != 0) { (void) dladm_errlist_append(errs, "failed to activate varpd instance: %s", strerror(ret)); - (void) dladm_overlay_walk_varpd_prop(handle, linkid, id, - dladm_overlay_activate_cb, errs); + (void) dladm_overlay_walk_varpd_prop(handle, attr->oa_linkid, + id, dladm_overlay_activate_cb, errs); (void) libvarpd_c_instance_destroy(vch, id); libvarpd_c_destroy(vch); - (void) dladm_overlay_delete(handle, linkid); return (dladm_errno2status(ret)); } bzero(&oia, sizeof (oia)); - oia.oia_linkid = linkid; + oia.oia_linkid = attr->oa_linkid; status = DLADM_STATUS_OK; ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_ACTIVATE, &oia); if (ret != 0) { @@ -595,20 +756,78 @@ dladm_overlay_create(dladm_handle_t handle, const char *name, (void) dladm_errlist_append(errs, "failed to activate " "device: %s", strerror(ret)); (void) libvarpd_c_instance_destroy(vch, id); - (void) dladm_overlay_walk_prop(handle, linkid, + (void) dladm_overlay_walk_prop(handle, attr->oa_linkid, dladm_overlay_activate_cb, errs, errs); status = dladm_errno2status(ret); - (void) libvarpd_c_instance_destroy(vch, id); } libvarpd_c_destroy(vch); - if (status != DLADM_STATUS_OK) - (void) dladm_overlay_delete(handle, linkid); return (status); } +dladm_status_t +dladm_overlay_create(dladm_handle_t handle, const char *name, + const char *encap, const char *search, uint64_t vid, + dladm_arg_list_t *props, dladm_errlist_t *errs, uint32_t flags) +{ + dladm_status_t status; + datalink_id_t linkid; + dladm_overlay_attr_t attr; + char errmsg[DLADM_STRSIZE]; + + if (strlcpy(attr.oa_name, name, sizeof (attr.oa_name)) >= + sizeof (attr.oa_name)) { + return (DLADM_STATUS_BADARG); + } + if (strlcpy(attr.oa_encap, encap, sizeof (attr.oa_encap)) >= + sizeof (attr.oa_encap)) { + return (DLADM_STATUS_BADARG); + } + if (strlcpy(attr.oa_search, search, sizeof (attr.oa_search)) >= + sizeof (attr.oa_search)) { + return (DLADM_STATUS_BADARG); + } + + status = varpd_enable_service(); + if (status != DLADM_STATUS_OK) + return (status); + + status = dladm_create_datalink_id(handle, name, DATALINK_CLASS_OVERLAY, + DL_ETHER, flags, &linkid); + if (status != DLADM_STATUS_OK) + return (status); + + attr.oa_linkid = linkid; + attr.oa_vid = vid; + attr.oa_flags = flags; + + status = i_dladm_overlay_create_sys(handle, &attr); + + if (status != DLADM_STATUS_OK) { + (void) dladm_destroy_datalink_id(handle, linkid, flags); + return (status); + } + + if ((flags & DLADM_OPT_PERSIST) != 0) { + status = dladm_overlay_persist_config(handle, &attr); + if (status != DLADM_STATUS_OK) { + (void) dladm_errlist_append(errs, "failed to create " + "persistent configuration for %s: %s", + attr.oa_name, dladm_status2str(status, errmsg)); + } + } + + if (status == DLADM_STATUS_OK) + status = i_dladm_overlay_commit_sys(handle, &attr, props, errs); + + if (status != DLADM_STATUS_OK) { + (void) dladm_overlay_delete(handle, linkid, flags); + (void) dladm_destroy_datalink_id(handle, linkid, flags); + } + return (status); +} typedef struct overlay_walk_cb { dladm_handle_t owc_handle; @@ -619,7 +838,6 @@ typedef struct overlay_walk_cb { uint_t owc_dest; } overlay_walk_cb_t; -/* ARGSUSED */ static int dladm_overlay_walk_cache_cb(varpd_client_handle_t *chdl, uint64_t varpdid, const struct ether_addr *key, const varpd_client_cache_entry_t *entry, @@ -681,7 +899,6 @@ dladm_overlay_walk_cache(dladm_handle_t handle, datalink_id_t linkid, return (dladm_errno2status(ret)); } -/* ARGSUSED */ dladm_status_t dladm_overlay_cache_flush(dladm_handle_t handle, datalink_id_t linkid) { @@ -703,7 +920,6 @@ dladm_overlay_cache_flush(dladm_handle_t handle, datalink_id_t linkid) return (dladm_errno2status(ret)); } -/* ARGSUSED */ dladm_status_t dladm_overlay_cache_delete(dladm_handle_t handle, datalink_id_t linkid, const struct ether_addr *key) @@ -726,7 +942,6 @@ dladm_overlay_cache_delete(dladm_handle_t handle, datalink_id_t linkid, return (dladm_errno2status(ret)); } -/* ARGSUSED */ dladm_status_t dladm_overlay_cache_set(dladm_handle_t handle, datalink_id_t linkid, const struct ether_addr *key, char *val) @@ -840,7 +1055,6 @@ send: return (dladm_errno2status(ret)); } -/* ARGSUSED */ dladm_status_t dladm_overlay_cache_get(dladm_handle_t handle, datalink_id_t linkid, const struct ether_addr *key, dladm_overlay_point_t *point) @@ -904,3 +1118,212 @@ dladm_overlay_status(dladm_handle_t handle, datalink_id_t linkid, func(handle, linkid, &dos, arg); return (DLADM_STATUS_OK); } + +/* + * dladm_parse_args() usually creates a dladm_arg_list_t by tokenising a + * delimited string and storing pointers to pieces of that string in the + * dladm_arg_info_t structure. Those pointers do not need to be individually + * freed. + * + * This function deals with property lists which have instead been built from + * the persistent datalink configuration database, in order to bring up an + * overlay at boot time. In this case, the properties have been retrieved + * one-by-one, duplicated with strdup(), and added to the list. When the list + * is finished with, this function takes care of freeing the memory. + */ +static void +i_dladm_overlay_props_free(dladm_handle_t handle, dladm_arg_list_t *props) +{ + uint_t i, j; + + for (i = 0; props != NULL && i < props->al_count; i++) { + dladm_arg_info_t *aip = &props->al_info[i]; + + /* For ai_name, we need to cast away the 'const' qualifier. */ + free((char *)aip->ai_name); + for (j = 0; j < aip->ai_count; j++) + free(aip->ai_val[j]); + } + free(props); +} + +static dladm_status_t +i_dladm_overlay_fetch_persistent_config(dladm_handle_t handle, + datalink_id_t linkid, dladm_overlay_attr_t *attrp, + dladm_arg_list_t **props) +{ + dladm_conf_t conf; + dladm_status_t status; + char attr[MAXLINKATTRLEN], last_attr[MAXLINKATTRLEN]; + char attrval[OVERLAY_PROP_SIZEMAX]; + size_t attrsz; + dladm_arg_list_t *list = NULL; + + *props = NULL; + + if ((status = dladm_getsnap_conf(handle, linkid, &conf)) != + DLADM_STATUS_OK) { + return (status); + } + + attrp->oa_linkid = linkid; + + status = dladm_get_conf_field(handle, conf, FVNETID, &attrp->oa_vid, + sizeof (attrp->oa_vid)); + if (status != DLADM_STATUS_OK) + goto done; + + status = dladm_get_conf_field(handle, conf, FENCAP, + attrp->oa_encap, sizeof (attrp->oa_encap)); + if (status != DLADM_STATUS_OK) + goto done; + + status = dladm_get_conf_field(handle, conf, FSEARCH, + attrp->oa_search, sizeof (attrp->oa_search)); + if (status != DLADM_STATUS_OK) + goto done; + + list = calloc(1, sizeof (dladm_arg_list_t)); + + *last_attr = '\0'; + while (dladm_getnext_conf_linkprop(handle, conf, last_attr, + attr, attrval, sizeof (attrval), &attrsz) == DLADM_STATUS_OK) { + dladm_arg_info_t *aip; + + (void) strlcpy(last_attr, attr, sizeof (last_attr)); + if (strchr(attr, '/') == NULL) + continue; + + aip = &list->al_info[list->al_count]; + bzero(aip, sizeof (dladm_arg_info_t)); + if ((aip->ai_name = strdup(attr)) == NULL) { + status = dladm_errno2status(errno); + break; + } + if ((aip->ai_val[0] = strdup(attrval)) == NULL) { + status = dladm_errno2status(errno); + break; + } + aip->ai_count = 1; + list->al_count++; + if (list->al_count >= DLADM_MAX_ARG_CNT) { + status = DLADM_STATUS_TOOMANYELEMENTS; + break; + } + } + +done: + + dladm_destroy_conf(handle, conf); + + if (status != DLADM_STATUS_OK) { + if (list != NULL) + i_dladm_overlay_props_free(handle, list); + return (status); + } + + *props = list; + return (DLADM_STATUS_OK); +} + +typedef struct dladm_overlay_up_arg_s { + dladm_errlist_t *errlist; +} dladm_overlay_up_arg_t; + +static int +i_dladm_overlay_up(dladm_handle_t handle, datalink_id_t linkid, void *arg) +{ + dladm_overlay_up_arg_t *argp = arg; + dladm_errlist_t *errs = argp->errlist; + datalink_class_t class; + dladm_status_t status; + dladm_overlay_attr_t attr; + dladm_arg_list_t *props; + char errmsg[DLADM_STRSIZE]; + + bzero(&attr, sizeof (attr)); + + status = dladm_datalink_id2info(handle, linkid, NULL, &class, + NULL, attr.oa_name, sizeof (attr.oa_name)); + if (status != DLADM_STATUS_OK) { + (void) dladm_errlist_append(errs, "failed to get info for " + "datalink id %u: %s", + linkid, dladm_status2str(status, errmsg)); + return (DLADM_STATUS_BADARG); + } + + if (class != DATALINK_CLASS_OVERLAY) { + (void) dladm_errlist_append(errs, "%s is not an overlay", + attr.oa_name); + return (DLADM_STATUS_BADARG); + } + + status = varpd_enable_service(); + if (status != DLADM_STATUS_OK) { + (void) dladm_errlist_append(errs, "failed to enable svc:/%s", + VARPD_SERVICE); + return (DLADM_WALK_TERMINATE); + } + + status = i_dladm_overlay_fetch_persistent_config(handle, linkid, + &attr, &props); + if (status != DLADM_STATUS_OK) { + (void) dladm_errlist_append(errs, "failed to retrieve " + "persistent configuration for %s: %s", + attr.oa_name, dladm_status2str(status, errmsg)); + return (DLADM_WALK_CONTINUE); + } + + status = i_dladm_overlay_create_sys(handle, &attr); + if (status != DLADM_STATUS_OK) { + (void) dladm_errlist_append(errs, + "failed to create overlay device %s: %s", + attr.oa_name, dladm_status2str(status, errmsg)); + goto out; + } + + status = i_dladm_overlay_commit_sys(handle, &attr, props, errs); + if (status != DLADM_STATUS_OK) { + (void) dladm_errlist_append(errs, + "failed to set properties for overlay device %s: %s", + attr.oa_name, dladm_status2str(status, errmsg)); + dladm_overlay_delete(handle, linkid, 0); + goto out; + } + + status = dladm_up_datalink_id(handle, linkid); + if (status != DLADM_STATUS_OK) { + (void) dladm_errlist_append(errs, + "failed to bring datalink up for overlay device %s: %s", + attr.oa_name, dladm_status2str(status, errmsg)); + dladm_overlay_delete(handle, linkid, 0); + goto out; + } + +out: + i_dladm_overlay_props_free(handle, props); + + return (DLADM_WALK_CONTINUE); +} + +dladm_status_t +dladm_overlay_up(dladm_handle_t handle, datalink_id_t linkid, + dladm_errlist_t *errs) +{ + dladm_overlay_up_arg_t overlay_arg = { + .errlist = errs + }; + + if (linkid == DATALINK_ALL_LINKID) { + (void) dladm_walk_datalink_id(i_dladm_overlay_up, handle, + &overlay_arg, DATALINK_CLASS_OVERLAY, + DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); + } else { + (void) i_dladm_overlay_up(handle, linkid, &overlay_arg); + } + + if (dladm_errlist_count(errs) == 0) + return (DLADM_STATUS_OK); + + return (DLADM_STATUS_FAILED); +} |