/* * Unpack a device path/nvlist pair to internal data list format. * Used to decode the nvlist format into the internal representation * when reading /etc/devices/devname_cache. * Note that the expiration counts are optional, for compatibility * with earlier instances of the cache. If not present, the * expire counts are initialized to defaults. */ static int sdev_ncache_unpack_nvlist(nvf_handle_t fd, nvlist_t *nvl, char *name) { nvp_devname_t *np; char **strs; int *cnts; uint_t nstrs, ncnts; int rval, i; ASSERT(fd == sdevfd_handle); ASSERT(RW_WRITE_HELD(nvf_lock(fd))); /* name of the sublist must match what we created */ if (strcmp(name, DP_DEVNAME_ID) != 0) { return (-1); } np = kmem_zalloc(sizeof (nvp_devname_t), KM_SLEEP); rval = nvlist_lookup_string_array(nvl, DP_DEVNAME_NCACHE_ID, &strs, &nstrs); if (rval) { kmem_free(np, sizeof (nvp_devname_t)); return (-1); } np->nvp_npaths = nstrs; np->nvp_paths = kmem_zalloc(nstrs * sizeof (char *), KM_SLEEP); for (i = 0; i < nstrs; i++) { np->nvp_paths[i] = i_ddi_strdup(strs[i], KM_SLEEP); } np->nvp_expirecnts = kmem_zalloc(nstrs * sizeof (int), KM_SLEEP); for (i = 0; i < nstrs; i++) { np->nvp_expirecnts[i] = sdev_nc_expirecnt; } rval = nvlist_lookup_int32_array(nvl, DP_DEVNAME_NC_EXPIRECNT_ID, &cnts, &ncnts); if (rval == 0) { ASSERT(ncnts == nstrs); ncnts = min(ncnts, nstrs); for (i = 0; i < nstrs; i++) { np->nvp_expirecnts[i] = cnts[i]; } } list_insert_tail(nvf_list(sdevfd_handle), np); return (0); }
/* * Convert a device path/nvlist pair to an nvp_list_t * Used to parse the nvlist format when reading * /etc/devices/devname_cache */ static nvp_list_t * sdev_nvl2nvp(nvlist_t *nvl, char *name) { nvp_devname_t *np; char **strs; int *cnts; uint_t nstrs, ncnts; int rval, i; /* name of the sublist must match what we created */ if (strcmp(name, DP_DEVNAME_ID) != 0) { return (NULL); } np = kmem_zalloc(sizeof (nvp_devname_t), KM_SLEEP); rval = nvlist_lookup_string_array(nvl, DP_DEVNAME_NCACHE_ID, &strs, &nstrs); if (rval) { kmem_free(np, sizeof (nvp_devname_t)); return (NULL); } np->nvp_npaths = nstrs; np->nvp_paths = kmem_zalloc(nstrs * sizeof (char *), KM_SLEEP); for (i = 0; i < nstrs; i++) { np->nvp_paths[i] = i_ddi_strdup(strs[i], KM_SLEEP); } np->nvp_expirecnts = kmem_zalloc(nstrs * sizeof (int), KM_SLEEP); for (i = 0; i < nstrs; i++) { np->nvp_expirecnts[i] = 4; /* XXX sdev_nc_expirecnt */ } rval = nvlist_lookup_int32_array(nvl, DP_DEVNAME_NC_EXPIRECNT_ID, &cnts, &ncnts); if (rval == 0) { ASSERT(ncnts == nstrs); ncnts = max(ncnts, nstrs); for (i = 0; i < nstrs; i++) { np->nvp_expirecnts[i] = cnts[i]; } } return (NVPLIST(np)); }
/* Calls the client callback function, if one is registered */ static void notifyClient(sysevent_t *ev) { nvlist_t *attr_list = NULL; uint64_t *val = NULL; int32_t *instance = NULL; int32_t *major = NULL; int valAllocated = 0; uint_t nelem = 0; int i = 0; int eventType = 0; int index = -1; void *pCallerData = NULL; char subClassName[256]; MP_BOOL becomingVisible = MP_FALSE; MP_OID_LIST *oidList = NULL; log(LOG_INFO, "notifyClient()", "- enter"); (void) strncpy(subClassName, sysevent_get_subclass_name(ev), 256); if (strstr(subClassName, "change")) { eventType = PROP_CHANGE; log(LOG_INFO, "notifyClient()", "- got a change event"); log(LOG_INFO, "notifyClient()", ": [%s]", subClassName); if (strncmp(subClassName, ESC_SUN_MP_PLUGIN_CHANGE, 255) == 0) { index = MP_OBJECT_TYPE_PLUGIN; } else if (strncmp(subClassName, ESC_SUN_MP_LU_CHANGE, 255) == 0) { index = MP_OBJECT_TYPE_MULTIPATH_LU; } else if (strncmp(subClassName, ESC_SUN_MP_PATH_CHANGE, 255) == 0) { index = MP_OBJECT_TYPE_PATH_LU; } else if (strncmp(subClassName, ESC_SUN_MP_INIT_PORT_CHANGE, 255) == 0) { index = MP_OBJECT_TYPE_INITIATOR_PORT; } else if (strncmp(subClassName, ESC_SUN_MP_TPG_CHANGE, 255) == 0) { index = MP_OBJECT_TYPE_TARGET_PORT_GROUP; } else if (strncmp(subClassName, ESC_SUN_MP_TARGET_PORT_CHANGE, 255) == 0) { index = MP_OBJECT_TYPE_TARGET_PORT; } else if (strncmp(subClassName, ESC_SUN_MP_DEV_PROD_CHANGE, 255) == 0) { index = MP_OBJECT_TYPE_DEVICE_PRODUCT; } } else if ((strstr(subClassName, "add")) || (strstr(subClassName, "initiator_register"))) { eventType = VISA_CHANGE; becomingVisible = MP_TRUE; log(LOG_INFO, "notifyClient()", "- got a visibility" " add event"); log(LOG_INFO, "notifyClient()", ": [%s]", subClassName); if (strncmp(subClassName, ESC_SUN_MP_LU_ADD, 255) == 0) { index = MP_OBJECT_TYPE_MULTIPATH_LU; } else if (strncmp(subClassName, ESC_SUN_MP_PATH_ADD, 255) == 0) { index = MP_OBJECT_TYPE_PATH_LU; } else if (strncmp(subClassName, ESC_DDI_INITIATOR_REGISTER, 244) == 0) { index = MP_OBJECT_TYPE_INITIATOR_PORT; } else if (strncmp(subClassName, ESC_SUN_MP_TPG_ADD, 255) == 0) { index = MP_OBJECT_TYPE_TARGET_PORT_GROUP; } else if (strncmp(subClassName, ESC_SUN_MP_TARGET_PORT_ADD, 255) == 0) { index = MP_OBJECT_TYPE_TARGET_PORT; } else if (strncmp(subClassName, ESC_SUN_MP_DEV_PROD_ADD, 255) == 0) { index = MP_OBJECT_TYPE_DEVICE_PRODUCT; } } else if ((strstr(subClassName, "remove")) || (strstr(subClassName, "initiator_unregister"))) { eventType = VISA_CHANGE; becomingVisible = MP_FALSE; log(LOG_INFO, "notifyClient()", "- got a visibility" " remove event"); log(LOG_INFO, "notifyClient()", ": [%s]", subClassName); if (strncmp(subClassName, ESC_SUN_MP_LU_REMOVE, 255) == 0) { index = MP_OBJECT_TYPE_MULTIPATH_LU; } else if (strncmp(subClassName, ESC_SUN_MP_PATH_REMOVE, 255) == 0) { index = MP_OBJECT_TYPE_PATH_LU; } else if (strncmp(subClassName, ESC_DDI_INITIATOR_UNREGISTER, 255) == 0) { index = MP_OBJECT_TYPE_INITIATOR_PORT; } else if (strncmp(subClassName, ESC_SUN_MP_TPG_REMOVE, 255) == 0) { index = MP_OBJECT_TYPE_TARGET_PORT_GROUP; } else if (strncmp(subClassName, ESC_SUN_MP_TARGET_PORT_REMOVE, 255) == 0) { index = MP_OBJECT_TYPE_TARGET_PORT; } else if (strncmp(subClassName, ESC_SUN_MP_DEV_PROD_REMOVE, 255) == 0) { index = MP_OBJECT_TYPE_DEVICE_PRODUCT; } } else { log(LOG_INFO, "notifyClient()", "- got an unsupported event"); return; } if (index < 0) { log(LOG_INFO, "notifyClient()", "- index is less than zero"); return; } if (eventType == VISA_CHANGE) { (void) pthread_mutex_lock(&g_visa_mutex); if (NULL == g_Visibility_Callback_List[index].pClientFn) { log(LOG_INFO, "notifyClient()", "- no visibility change callback to notify"); (void) pthread_mutex_unlock(&g_visa_mutex); return; } (void) pthread_mutex_unlock(&g_visa_mutex); } if (eventType == PROP_CHANGE) { (void) pthread_mutex_lock(&g_prop_mutex); if (NULL == g_Property_Callback_List[index].pClientFn) { log(LOG_INFO, "notifyClient()", "- no property change callback to notify"); (void) pthread_mutex_unlock(&g_prop_mutex); return; } (void) pthread_mutex_unlock(&g_prop_mutex); } (void) sysevent_get_attr_list(ev, &attr_list); if (NULL != attr_list) { if ((VISA_CHANGE == eventType) && (MP_OBJECT_TYPE_PLUGIN == index)) { val = (uint64_t *)malloc(sizeof (uint64_t)); valAllocated = 1; /* * We have no well-defined way to determine our OSN. * Currently the common library uses 0 as OSN for every * plugin, so just use 0. If the OSN assigned by the * common library changed, this code would have to be * updated. */ *val = 0; nelem = 1; } else if ((VISA_CHANGE == eventType) && (MP_OBJECT_TYPE_INITIATOR_PORT == index)) { (void) nvlist_lookup_int32_array(attr_list, DDI_INSTANCE, &instance, &nelem); log(LOG_INFO, "notifyClient()", "- event (PHCI_INSTANCE) has [%d] elements", nelem); (void) nvlist_lookup_int32_array(attr_list, DDI_DRIVER_MAJOR, &major, &nelem); log(LOG_INFO, "notifyClient()", "- event (PHCI_DRIVER_MAJOR) has [%d] elements", nelem); if ((NULL != instance) & (NULL != major)) { val = (uint64_t *)malloc(sizeof (uint64_t)); valAllocated = 1; *val = 0; *val = MP_STORE_INST_TO_ID(*instance, *val); *val = MP_STORE_MAJOR_TO_ID(*major, *val); nelem = 1; } else { nelem = 0; } } else { (void) nvlist_lookup_uint64_array(attr_list, OIDLIST, &val, &nelem); log(LOG_INFO, "notifyClient()", "- event has [%d] elements", nelem); } if (nelem > 0) { for (i = 0; i < nelem; i++) { log(LOG_INFO, "notifyClient()", "- event [%d] = %llx", i, val[i]); } oidList = createOidList(nelem); if (NULL == oidList) { log(LOG_INFO, "notifyClient()", "- unable to create MP_OID_LIST"); log(LOG_INFO, "notifyClient()", "- error exit"); nvlist_free(attr_list); return; } oidList->oidCount = nelem; for (i = 0; i < nelem; i++) { oidList->oids[i].objectType = index; oidList->oids[i].ownerId = g_pluginOwnerID; oidList->oids[i].objectSequenceNumber = val[i]; } if (valAllocated) { free(val); } for (i = 0; i < oidList->oidCount; i++) { log(LOG_INFO, "notifyClient()", "oidList->oids[%d].objectType" " = %d", i, oidList->oids[i].objectType); log(LOG_INFO, "notifyClient()", "oidList->oids[%d].ownerId" " = %d", i, oidList->oids[i].ownerId); log(LOG_INFO, "notifyClient()", "oidList->oids[%d].objectSequenceNumber" " = %llx", i, oidList->oids[i].objectSequenceNumber); } if (eventType == PROP_CHANGE) { (void) pthread_mutex_lock(&g_prop_mutex); pCallerData = g_Property_Callback_List[index]. pCallerData; (g_Property_Callback_List[index].pClientFn) (oidList, pCallerData); (void) pthread_mutex_unlock(&g_prop_mutex); } else if (eventType == VISA_CHANGE) { (void) pthread_mutex_lock(&g_visa_mutex); pCallerData = g_Visibility_Callback_List[index]. pCallerData; (g_Visibility_Callback_List[index].pClientFn) (becomingVisible, oidList, pCallerData); (void) pthread_mutex_unlock(&g_visa_mutex); } } nvlist_free(attr_list); } log(LOG_INFO, "notifyClient()", "- exit"); }
static int prop_getval(tnode_t *node, const char *pgname, const char *pname, void *val, topo_type_t type, uint_t *nelems, int *err) { int i, j, ret = 0; topo_hdl_t *thp = node->tn_hdl; topo_propval_t *pv; topo_node_lock(node); if ((pv = prop_get(node, pgname, pname, NULL, err)) == NULL) return (get_properror(node, err, *err)); if (pv->tp_type != type) return (get_properror(node, err, ETOPO_PROP_TYPE)); switch (type) { case TOPO_TYPE_INT32: ret = nvlist_lookup_int32(pv->tp_val, TOPO_PROP_VAL_VAL, (int32_t *)val); break; case TOPO_TYPE_UINT32: ret = nvlist_lookup_uint32(pv->tp_val, TOPO_PROP_VAL_VAL, (uint32_t *)val); break; case TOPO_TYPE_INT64: ret = nvlist_lookup_int64(pv->tp_val, TOPO_PROP_VAL_VAL, (int64_t *)val); break; case TOPO_TYPE_UINT64: ret = nvlist_lookup_uint64(pv->tp_val, TOPO_PROP_VAL_VAL, (uint64_t *)val); break; case TOPO_TYPE_DOUBLE: ret = nvlist_lookup_double(pv->tp_val, TOPO_PROP_VAL_VAL, (double *)val); break; case TOPO_TYPE_STRING: { char *str; ret = nvlist_lookup_string(pv->tp_val, TOPO_PROP_VAL_VAL, &str); if (ret == 0) { char *s2; if ((s2 = topo_hdl_strdup(thp, str)) == NULL) ret = -1; else *(char **)val = s2; } break; } case TOPO_TYPE_FMRI: { nvlist_t *nvl; ret = nvlist_lookup_nvlist(pv->tp_val, TOPO_PROP_VAL_VAL, &nvl); if (ret == 0) ret = topo_hdl_nvdup(thp, nvl, (nvlist_t **)val); break; } case TOPO_TYPE_INT32_ARRAY: { int32_t *a1, *a2; if ((ret = nvlist_lookup_int32_array(pv->tp_val, TOPO_PROP_VAL_VAL, &a2, nelems)) != 0) break; if ((a1 = topo_hdl_alloc(thp, sizeof (int32_t) * *nelems)) == NULL) { ret = ETOPO_NOMEM; break; } for (i = 0; i < *nelems; ++i) a1[i] = a2[i]; *(int32_t **)val = a1; break; } case TOPO_TYPE_UINT32_ARRAY: { uint32_t *a1, *a2; if ((ret = nvlist_lookup_uint32_array(pv->tp_val, TOPO_PROP_VAL_VAL, &a2, nelems)) != 0) break; if ((a1 = topo_hdl_alloc(thp, sizeof (uint32_t) * *nelems)) == NULL) { ret = ETOPO_NOMEM; break; } for (i = 0; i < *nelems; ++i) a1[i] = a2[i]; *(uint32_t **)val = a1; break; } case TOPO_TYPE_INT64_ARRAY: { int64_t *a1, *a2; if ((ret = nvlist_lookup_int64_array(pv->tp_val, TOPO_PROP_VAL_VAL, &a2, nelems)) != 0) break; if ((a1 = topo_hdl_alloc(thp, sizeof (int64_t) * *nelems)) == NULL) { ret = ETOPO_NOMEM; break; } for (i = 0; i < *nelems; ++i) a1[i] = a2[i]; *(int64_t **)val = a1; break; } case TOPO_TYPE_UINT64_ARRAY: { uint64_t *a1, *a2; if ((ret = nvlist_lookup_uint64_array(pv->tp_val, TOPO_PROP_VAL_VAL, &a2, nelems)) != 0) break; if ((a1 = topo_hdl_alloc(thp, sizeof (uint64_t) * *nelems)) == NULL) { ret = ETOPO_NOMEM; break; } for (i = 0; i < *nelems; ++i) a1[i] = a2[i]; *(uint64_t **)val = a1; break; } case TOPO_TYPE_STRING_ARRAY: { char **a1, **a2; if ((ret = nvlist_lookup_string_array(pv->tp_val, TOPO_PROP_VAL_VAL, &a2, nelems)) != 0) break; if ((a1 = topo_hdl_alloc(thp, sizeof (char *) * *nelems)) == NULL) { ret = ETOPO_NOMEM; break; } for (i = 0; i < *nelems; ++i) { if ((a1[i] = topo_hdl_strdup(thp, a2[i])) == NULL) { for (j = 0; j < i; ++j) topo_hdl_free(thp, a1[j], sizeof (char *)); topo_hdl_free(thp, a1, sizeof (char *) * *nelems); break; } } *(char ***)val = a1; break; } case TOPO_TYPE_FMRI_ARRAY: { nvlist_t **a1, **a2; if ((ret = nvlist_lookup_nvlist_array(pv->tp_val, TOPO_PROP_VAL_VAL, &a2, nelems)) != 0) break; if ((a1 = topo_hdl_alloc(thp, sizeof (nvlist_t *) * *nelems)) == NULL) { ret = ETOPO_NOMEM; break; } for (i = 0; i < *nelems; ++i) { if (topo_hdl_nvdup(thp, a2[i], &a1[i]) < 0) { for (j = 0; j < i; ++j) nvlist_free(a1[j]); topo_hdl_free(thp, a1, sizeof (nvlist_t *) * *nelems); break; } } *(nvlist_t ***)val = a1; break; } default: ret = ETOPO_PROP_NOENT; } if (ret != 0) if (ret == ENOENT) return (get_properror(node, err, ETOPO_PROP_NOENT)); else if (ret < ETOPO_UNKNOWN) return (get_properror(node, err, ETOPO_PROP_NVL)); else return (get_properror(node, err, ret)); topo_node_unlock(node); return (0); }
/* * pset_validate_remove() * Check to see if the requested cpu removal would be acceptable. * Returns RCM_FAILURE if not. */ static int pset_validate_remove(nvlist_t *nvl, char **errorp) { int error = RCM_SUCCESS; int32_t old_total, new_total, removed_total; processorid_t *removed_list = NULL; /* list terminated by (-1). */ processorid_t *old_cpu_list = NULL, *new_cpu_list = NULL; int i, j; pool_conf_t *conf; pool_value_t *pvals[] = { NULL, NULL }; pool_resource_t **res = NULL; uint_t nelem; const char *generic_error = gettext("POOL: Error processing request\n"); if ((conf = pool_conf_alloc()) == NULL) return (RCM_FAILURE); if (pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY) < 0) { rcm_log_message(RCM_TRACE1, "POOL: failed to parse config file: '%s'\n", pool_dynamic_location()); pool_conf_free(conf); return (RCM_SUCCESS); } if ((error = nvlist_lookup_int32(nvl, "old_total", &old_total)) != 0) { (void) pool_conf_close(conf); pool_conf_free(conf); rcm_log_message(RCM_ERROR, gettext("POOL: unable to find 'old_total' in nvlist: %s\n"), strerror(error)); *errorp = strdup(generic_error); return (RCM_FAILURE); } if ((error = nvlist_lookup_int32(nvl, "new_total", &new_total)) != 0) { (void) pool_conf_close(conf); pool_conf_free(conf); rcm_log_message(RCM_ERROR, gettext("POOL: unable to find 'new_total' in nvlist: %s\n"), strerror(error)); *errorp = strdup(generic_error); return (RCM_FAILURE); } if (new_total >= old_total) { (void) pool_conf_close(conf); pool_conf_free(conf); /* * This doesn't look like a cpu removal. */ rcm_log_message(RCM_TRACE1, gettext("POOL: 'old_total' (%d) is less than 'new_total' " "(%d)\n"), old_total, new_total); return (RCM_SUCCESS); } if ((removed_list = malloc((old_total - new_total + 1) * sizeof (int))) == NULL) { rcm_log_message(RCM_ERROR, gettext("POOL: malloc failed: %s\n"), strerror(errno)); error = RCM_FAILURE; goto out; } if ((error = nvlist_lookup_int32_array(nvl, "old_cpu_list", &old_cpu_list, &nelem)) != 0) { rcm_log_message(RCM_ERROR, gettext("POOL: 'old_cpu_list' not found in nvlist: %s\n"), strerror(error)); error = RCM_FAILURE; goto out; } if ((int32_t)nelem != old_total) { rcm_log_message(RCM_ERROR, gettext("POOL: 'old_cpu_list' size mismatch: %1$d vs " "%2$d\n"), nelem, old_total); error = RCM_FAILURE; goto out; } if ((error = nvlist_lookup_int32_array(nvl, "new_cpu_list", &new_cpu_list, &nelem)) != 0) { rcm_log_message(RCM_ERROR, gettext("POOL: 'new_cpu_list' not found in nvlist: %s\n"), strerror(error)); error = RCM_FAILURE; goto out; } if (nelem != new_total) { rcm_log_message(RCM_ERROR, gettext("POOL: 'new_cpu_list' size mismatch: %1$d vs " "%2$d\n"), nelem, new_total); error = RCM_FAILURE; goto out; } for (i = 0, removed_total = 0; i < old_total; i++) { for (j = 0; j < new_total; j++) if (old_cpu_list[i] == new_cpu_list[j]) break; if (j == new_total) /* not found in new_cpu_list */ removed_list[removed_total++] = old_cpu_list[i]; } removed_list[removed_total] = -1; if (removed_total != (old_total - new_total)) { rcm_log_message(RCM_ERROR, gettext("POOL: error finding removed cpu list\n")); error = RCM_FAILURE; goto out; } if ((pvals[0] = pool_value_alloc()) == NULL) { rcm_log_message(RCM_ERROR, gettext("POOL: pool_value_alloc" " failed: %s\n"), strerror(errno)); error = RCM_FAILURE; goto out; } /* * Look for resources with "'type' = 'pset'" */ (void) pool_value_set_name(pvals[0], "type"); (void) pool_value_set_string(pvals[0], "pset"); if ((res = pool_query_resources(conf, &nelem, pvals)) == NULL) { rcm_log_message(RCM_ERROR, gettext("POOL: No psets found in configuration\n")); pool_value_free(pvals[0]); error = RCM_FAILURE; goto out; } pool_value_free(pvals[0]); for (i = 0; res[i] != NULL; i++) /* * Ask each pset if removing these cpus would cause it to go * below it's minimum value. */ if (pool_check_pset(conf, res[i], removed_list, errorp) < 0) { error = RCM_FAILURE; break; } free(res); out: if (removed_list) free(removed_list); if (conf) { (void) pool_conf_close(conf); pool_conf_free(conf); } /* * Set the error string if not already set. */ if (error != RCM_SUCCESS && *errorp == NULL) *errorp = strdup(generic_error); return (error); }
static int tokenmt_modify_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags) { nvlist_t *nvlp; int err = 0, err2; uint8_t config_type; char *next_action_name; ipp_action_id_t next_action; uint32_t rate, cbs, pbs; tokenmt_cfg_t *cfg_parms, *old_cfg; tokenmt_data_t *tokenmt_data; uint32_t bstats, mode; int32_t *colour_tbl; uint_t nelem = 64; nvlp = *nvlpp; *nvlpp = NULL; /* nvlist should be NULL when this returns */ if ((err = nvlist_lookup_byte(nvlp, IPP_CONFIG_TYPE, &config_type)) != 0) { nvlist_free(nvlp); tokenmt0dbg(("tokenmt_modify_action: invalid configuration "\ "type")); return (err); } if (config_type != IPP_SET) { nvlist_free(nvlp); tokenmt0dbg(("tokenmt_modify_action: invalid configuration "\ "type %d", config_type)); return (EINVAL); } tokenmt_data = (tokenmt_data_t *)ipp_action_get_ptr(aid); old_cfg = tokenmt_data->cfg_parms; cfg_parms = kmem_zalloc(TOKENMT_CFG_SZ, KM_NOSLEEP); if (cfg_parms == NULL) { nvlist_free(nvlp); tokenmt0dbg(("tokenmt_modify_action: memory allocation "\ "failure\n")); return (ENOMEM); } /* Just copy all and change as needed */ bcopy(old_cfg, cfg_parms, TOKENMT_CFG_SZ); /* parse red action name, if present */ if ((err = nvlist_lookup_string(nvlp, TOKENMT_RED_ACTION_NAME, &next_action_name)) == 0) { /* Get action id */ if ((next_action = ipp_action_lookup(next_action_name)) == IPP_ACTION_INVAL) { nvlist_free(nvlp); tokenmt0dbg(("tokenmt_modify_action: next_action "\ "invalid")); kmem_free(cfg_parms, TOKENMT_CFG_SZ); return (EINVAL); } cfg_parms->red_action = next_action; } /* parse yellow action name, if present */ if ((err = nvlist_lookup_string(nvlp, TOKENMT_YELLOW_ACTION_NAME, &next_action_name)) == 0) { /* Get action id */ if ((next_action = ipp_action_lookup(next_action_name)) == IPP_ACTION_INVAL) { nvlist_free(nvlp); tokenmt0dbg(("tokenmt_modify_action: next_action "\ "invalid")); kmem_free(cfg_parms, TOKENMT_CFG_SZ); return (EINVAL); } cfg_parms->yellow_action = next_action; } else { cfg_parms->yellow_action = TOKENMT_NO_ACTION; } /* parse green action name, if present */ if ((err = nvlist_lookup_string(nvlp, TOKENMT_GREEN_ACTION_NAME, &next_action_name)) == 0) { /* Get action id */ if ((next_action = ipp_action_lookup(next_action_name)) == IPP_ACTION_INVAL) { nvlist_free(nvlp); tokenmt0dbg(("tokenmt_modify_action: next_action "\ "invalid")); kmem_free(cfg_parms, TOKENMT_CFG_SZ); return (EINVAL); } cfg_parms->green_action = next_action; } /* parse committed rate, if present */ if ((err = nvlist_lookup_uint32(nvlp, TOKENMT_COMMITTED_RATE, &rate)) == 0) { if (rate == 0) { nvlist_free(nvlp); tokenmt0dbg(("tokenmt_modify_action: invalid "\ "committed rate %u\n", cfg_parms->committed_rate)); kmem_free(cfg_parms, TOKENMT_CFG_SZ); return (EINVAL); } cfg_parms->committed_rate = rate; } /* parse committed burst, if present */ if (nvlist_lookup_uint32(nvlp, TOKENMT_COMMITTED_BURST, &cbs) == 0) { cfg_parms->committed_burst = cbs; } if (nvlist_lookup_uint32(nvlp, TOKENMT_PEAK_BURST, &pbs) == 0) { cfg_parms->peak_burst = pbs; } else { cfg_parms->peak_burst = 0; } /* If the peak rate is not specified, then it means single rate meter */ if (nvlist_lookup_uint32(nvlp, TOKENMT_PEAK_RATE, &rate) == 0) { cfg_parms->peak_rate = rate; if ((rate == 0) || (rate < cfg_parms->committed_rate)) { nvlist_free(nvlp); tokenmt0dbg(("tokenmt_modify_action: invalid "\ "committed rate %u\n", cfg_parms->committed_rate)); kmem_free(cfg_parms, TOKENMT_CFG_SZ); return (EINVAL); } cfg_parms->tokenmt_type = TRTCL_TOKENMT; } else { cfg_parms->peak_rate = 0; cfg_parms->tokenmt_type = SRTCL_TOKENMT; } if (cfg_parms->yellow_action == TOKENMT_NO_ACTION) { if ((cfg_parms->peak_burst != 0) || (cfg_parms->tokenmt_type == TRTCL_TOKENMT)) { nvlist_free(nvlp); tokenmt0dbg(("tokenmt_modify_action: yellow action "\ "missing\n")); kmem_free(cfg_parms, TOKENMT_CFG_SZ); return (EINVAL); } } else { if ((cfg_parms->tokenmt_type != TRTCL_TOKENMT) && (cfg_parms->peak_burst == 0)) { nvlist_free(nvlp); tokenmt0dbg(("tokenmt_modify_action: peak "\ "burst/rate missing\n")); kmem_free(cfg_parms, TOKENMT_CFG_SZ); return (EINVAL); } } /* Validate the committed and peak burst size */ if (cfg_parms->tokenmt_type == SRTCL_TOKENMT) { if ((cfg_parms->committed_burst == 0) && (cfg_parms->peak_burst == 0)) { nvlist_free(nvlp); tokenmt0dbg(("tokenmt_modify_action: at least one "\ "burst size must be non-zero\n")); kmem_free(cfg_parms, TOKENMT_CFG_SZ); return (EINVAL); } } else { /* TRTCL_TOKENMT */ if ((cfg_parms->committed_burst == 0) || (cfg_parms->peak_burst == 0)) { nvlist_free(nvlp); tokenmt0dbg(("tokenmt_modify_action: both the "\ "burst sizes must be non-zero\n")); kmem_free(cfg_parms, TOKENMT_CFG_SZ); return (EINVAL); } } /* parse mode */ if (nvlist_lookup_uint32(nvlp, TOKENMT_COLOUR_AWARE, &mode) == 0) { cfg_parms->colour_aware = (mode == 0) ? B_FALSE : B_TRUE; } else { cfg_parms->colour_aware = B_FALSE; } if (cfg_parms->colour_aware) { if (nvlist_lookup_int32_array(nvlp, TOKENMT_COLOUR_MAP, &colour_tbl, &nelem) == 0) { int count; for (count = 0; count < 64; count++) { if (colour_tbl[count] == -1) continue; cfg_parms->dscp_to_colour[count] = colour_tbl[count]; } } else { bcopy(default_dscp_to_colour, cfg_parms->dscp_to_colour, sizeof (default_dscp_to_colour)); } } /* parse stats, if present */ if (nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, &bstats) == 0) { cfg_parms->stats = (bstats == 0) ? B_FALSE : B_TRUE; if (cfg_parms->stats && !old_cfg->stats) { if ((err = tokenmt_statinit(aid, tokenmt_data)) != 0) { nvlist_free(nvlp); kmem_free(cfg_parms, TOKENMT_CFG_SZ); return (err); } } else if (!cfg_parms->stats && old_cfg->stats) { ipp_stat_destroy(tokenmt_data->stats); } } /* Can we ref all the new actions? */ if ((err = ipp_action_ref(aid, cfg_parms->red_action, flags)) != 0) { tokenmt0dbg(("tokenmt_modify_data: can't ref. red action\n")); kmem_free(cfg_parms, TOKENMT_CFG_SZ); return (err); } if ((err = ipp_action_ref(aid, cfg_parms->green_action, flags)) != 0) { tokenmt0dbg(("tokenmt_modify_data:can't ref. green action\n")); err2 = ipp_action_unref(aid, cfg_parms->red_action, flags); ASSERT(err2 == 0); kmem_free(cfg_parms, TOKENMT_CFG_SZ); return (err); } if (cfg_parms->yellow_action != TOKENMT_NO_ACTION) { if ((err = ipp_action_ref(aid, cfg_parms->yellow_action, flags)) != 0) { tokenmt0dbg(("tokenmt_modify_data:can't ref. yellow "\ "action\n")); err2 = ipp_action_unref(aid, cfg_parms->red_action, flags); ASSERT(err2 == 0); err2 = ipp_action_unref(aid, cfg_parms->green_action, flags); ASSERT(err2 == 0); kmem_free(cfg_parms, TOKENMT_CFG_SZ); return (err); } } /* Actually modify the configuration */ mutex_enter(&tokenmt_data->tokenmt_lock); tokenmt_data->cfg_parms = cfg_parms; mutex_exit(&tokenmt_data->tokenmt_lock); /* Un-ref the old actions */ err = ipp_action_unref(aid, old_cfg->red_action, flags); ASSERT(err == 0); if (old_cfg->yellow_action != TOKENMT_NO_ACTION) { err = ipp_action_unref(aid, old_cfg->yellow_action, flags); ASSERT(err == 0); } err = ipp_action_unref(aid, old_cfg->green_action, flags); ASSERT(err == 0); /* Free the old configuration */ kmem_free(old_cfg, TOKENMT_CFG_SZ); return (0); }
/* ARGSUSED */ static int tokenmt_create_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags) { nvlist_t *nvlp; tokenmt_data_t *tokenmt_data; char *next_action; tokenmt_cfg_t *cfg_parms; uint32_t mode; uint32_t bstats; int rc, rc2; int32_t *colour_tbl; uint_t nelem = 64; nvlp = *nvlpp; *nvlpp = NULL; /* nvlist should be NULL on return */ if ((cfg_parms = kmem_zalloc(TOKENMT_CFG_SZ, KM_NOSLEEP)) == NULL) { nvlist_free(nvlp); return (ENOMEM); } /* parse red next action name */ if ((rc = nvlist_lookup_string(nvlp, TOKENMT_RED_ACTION_NAME, &next_action)) != 0) { nvlist_free(nvlp); tokenmt0dbg(("tokenmt_create_action:invalid config, red "\ "action name missing\n")); kmem_free(cfg_parms, TOKENMT_CFG_SZ); return (rc); } if ((cfg_parms->red_action = ipp_action_lookup(next_action)) == IPP_ACTION_INVAL) { nvlist_free(nvlp); tokenmt0dbg(("tokenmt_create_action: red action invalid\n")); kmem_free(cfg_parms, TOKENMT_CFG_SZ); return (EINVAL); } /* parse yellow next action name, if present this is Two Rate meter */ if ((rc = nvlist_lookup_string(nvlp, TOKENMT_YELLOW_ACTION_NAME, &next_action)) == 0) { if ((cfg_parms->yellow_action = ipp_action_lookup(next_action)) == IPP_ACTION_INVAL) { nvlist_free(nvlp); tokenmt0dbg(("tokenmt_create_action: yellow action "\ "invalid\n")); kmem_free(cfg_parms, TOKENMT_CFG_SZ); return (EINVAL); } } else { cfg_parms->yellow_action = TOKENMT_NO_ACTION; } /* parse green next action name */ if ((rc = nvlist_lookup_string(nvlp, TOKENMT_GREEN_ACTION_NAME, &next_action)) != 0) { nvlist_free(nvlp); tokenmt0dbg(("tokenmt_create_action:invalid config, green " \ "action name missing\n")); kmem_free(cfg_parms, TOKENMT_CFG_SZ); return (rc); } if ((cfg_parms->green_action = ipp_action_lookup(next_action)) == IPP_ACTION_INVAL) { nvlist_free(nvlp); tokenmt0dbg(("tokenmt_create_action: green action invalid\n")); kmem_free(cfg_parms, TOKENMT_CFG_SZ); return (EINVAL); } /* parse committed rate - in kilo bits / sec */ if ((rc = nvlist_lookup_uint32(nvlp, TOKENMT_COMMITTED_RATE, &cfg_parms->committed_rate)) != 0) { nvlist_free(nvlp); tokenmt0dbg(("tokenmt_create_action: invalid config, "\ " committed rate missing\n")); kmem_free(cfg_parms, TOKENMT_CFG_SZ); return (rc); } if (cfg_parms->committed_rate == 0) { nvlist_free(nvlp); tokenmt0dbg(("tokenmt_create_action: invalid committed rate, "\ "%u\n", cfg_parms->committed_rate)); kmem_free(cfg_parms, TOKENMT_CFG_SZ); return (EINVAL); } /* parse committed burst in bits */ if ((rc = nvlist_lookup_uint32(nvlp, TOKENMT_COMMITTED_BURST, &cfg_parms->committed_burst)) != 0) { nvlist_free(nvlp); tokenmt0dbg(("tokenmt_create_action: invalid config, "\ " committed burst missing\n")); kmem_free(cfg_parms, TOKENMT_CFG_SZ); return (rc); } /* * If the peak burst size is specified, make sure we have the * yellow action. */ if ((rc = nvlist_lookup_uint32(nvlp, TOKENMT_PEAK_BURST, &cfg_parms->peak_burst)) == 0) { if (cfg_parms->yellow_action == TOKENMT_NO_ACTION) { nvlist_free(nvlp); tokenmt0dbg(("tokenmt_create_action: peak burst "\ "specified without yellow action\n")); kmem_free(cfg_parms, TOKENMT_CFG_SZ); return (EINVAL); } } else if (cfg_parms->yellow_action != TOKENMT_NO_ACTION) { nvlist_free(nvlp); tokenmt0dbg(("tokenmt_create_action: peak burst must be "\ "provided with yellow action\n")); kmem_free(cfg_parms, TOKENMT_CFG_SZ); return (EINVAL); } /* Check if we have a peak_rate */ if ((rc = nvlist_lookup_uint32(nvlp, TOKENMT_PEAK_RATE, &cfg_parms->peak_rate)) == 0) { if (cfg_parms->yellow_action == TOKENMT_NO_ACTION) { nvlist_free(nvlp); tokenmt0dbg(("tokenmt_create_action: peak rate "\ "specified without yellow action\n")); kmem_free(cfg_parms, TOKENMT_CFG_SZ); return (EINVAL); } else if ((cfg_parms->peak_rate == 0) || (cfg_parms->peak_rate < cfg_parms->committed_rate)) { nvlist_free(nvlp); tokenmt0dbg(("tokenmt_create_action: invalid "\ "peak rate, %u\n", cfg_parms->peak_rate)); kmem_free(cfg_parms, TOKENMT_CFG_SZ); return (EINVAL); } cfg_parms->tokenmt_type = TRTCL_TOKENMT; } else { cfg_parms->tokenmt_type = SRTCL_TOKENMT; } /* Validate the committed and peak burst size */ if (cfg_parms->tokenmt_type == SRTCL_TOKENMT) { if ((cfg_parms->committed_burst == 0) && (cfg_parms->peak_burst == 0)) { nvlist_free(nvlp); tokenmt0dbg(("tokenmt_create_action: at least one "\ "burst size must be non-zero\n")); kmem_free(cfg_parms, TOKENMT_CFG_SZ); return (EINVAL); } } else { /* TRTCL_TOKENMT */ if ((cfg_parms->committed_burst == 0) || (cfg_parms->peak_burst == 0)) { nvlist_free(nvlp); tokenmt0dbg(("tokenmt_create_action: both the "\ "burst sizes must be non-zero\n")); kmem_free(cfg_parms, TOKENMT_CFG_SZ); return (EINVAL); } } /* just copy default colour mapping */ bcopy(default_dscp_to_colour, cfg_parms->dscp_to_colour, sizeof (default_dscp_to_colour)); /* parse mode, if present */ if ((rc = nvlist_lookup_uint32(nvlp, TOKENMT_COLOUR_AWARE, &mode)) != 0) { cfg_parms->colour_aware = B_FALSE; } else { cfg_parms->colour_aware = (mode == 0) ? B_FALSE : B_TRUE; } /* Get the dscp to colour mapping array */ if (cfg_parms->colour_aware) { if ((rc = nvlist_lookup_int32_array(nvlp, TOKENMT_COLOUR_MAP, &colour_tbl, &nelem)) == 0) { int count; for (count = 0; count < 64; count++) { if (colour_tbl[count] == -1) continue; cfg_parms->dscp_to_colour[count] = colour_tbl[count]; } } } /* parse stats */ if ((rc = nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, &bstats)) != 0) { cfg_parms->stats = B_FALSE; } else { cfg_parms->stats = (bstats == 0) ? B_FALSE : B_TRUE; } nvlist_free(nvlp); /* Initialize other stuff */ tokenmt_data = kmem_zalloc(TOKENMT_DATA_SZ, KM_NOSLEEP); if (tokenmt_data == NULL) { kmem_free(cfg_parms, TOKENMT_CFG_SZ); return (ENOMEM); } /* Initialize stats, if required */ if (cfg_parms->stats) { if ((rc = tokenmt_statinit(aid, tokenmt_data)) != 0) { kmem_free(cfg_parms, TOKENMT_CFG_SZ); kmem_free(tokenmt_data, TOKENMT_DATA_SZ); return (rc); } } /* set action chain reference */ if ((rc = ipp_action_ref(aid, cfg_parms->red_action, flags)) != 0) { tokenmt0dbg(("tokenmt_create_action: ipp_action_ref " \ "returned with error %d", rc)); goto cleanup; } if ((rc = ipp_action_ref(aid, cfg_parms->green_action, flags)) != 0) { tokenmt0dbg(("tokenmt_create_action: ipp_action_ref " \ "returned with error %d", rc)); rc2 = ipp_action_unref(aid, cfg_parms->red_action, flags); ASSERT(rc2 == 0); goto cleanup; } if (cfg_parms->yellow_action != TOKENMT_NO_ACTION) { if ((rc = ipp_action_ref(aid, cfg_parms->yellow_action, flags)) != 0) { tokenmt0dbg(("tokenmt_create_action: ipp_action_ref "\ "returned with error %d", rc)); rc2 = ipp_action_unref(aid, cfg_parms->red_action, flags); ASSERT(rc2 == 0); rc2 = ipp_action_unref(aid, cfg_parms->green_action, flags); ASSERT(rc2 == 0); goto cleanup; } } tokenmt_data->cfg_parms = cfg_parms; tokenmt_data->committed_tokens = cfg_parms->committed_burst; tokenmt_data->peak_tokens = cfg_parms->peak_burst; tokenmt_data->last_seen = gethrtime(); mutex_init(&tokenmt_data->tokenmt_lock, NULL, MUTEX_DEFAULT, 0); ipp_action_set_ptr(aid, (void *)tokenmt_data); return (0); cleanup: if (cfg_parms->stats) { ipp_stat_destroy(tokenmt_data->stats); } kmem_free(cfg_parms, TOKENMT_CFG_SZ); kmem_free(tokenmt_data, TOKENMT_DATA_SZ); return (rc); }