/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * XXX duplicate define */ #define DLADM_PROP_VAL_MAX 32 static dladm_status_t i_dladm_set_flowprop_db(const char *, const char *, char **, uint_t); static dladm_status_t i_dladm_get_flowprop_db(const char *, const char *, char **, uint_t *); static fpd_getf_t do_get_maxbw; static fpd_setf_t do_set_maxbw; static fpd_checkf_t do_check_maxbw; static fpd_getf_t do_get_priority; static fpd_setf_t do_set_priority; static fpd_checkf_t do_check_priority; static fprop_desc_t prop_table[] = { { "maxbw", { "", NULL }, NULL, 0, B_FALSE, do_set_maxbw, NULL, do_get_maxbw, do_check_maxbw}, { "priority", { "", NULL }, NULL, 0, B_FALSE, do_set_priority, NULL, do_get_priority, do_check_priority} }; #define DLADM_MAX_FLOWPROPS (sizeof (prop_table) / sizeof (fprop_desc_t)) static prop_table_t prop_tbl = { prop_table, DLADM_MAX_FLOWPROPS }; static resource_prop_t rsrc_prop_table[] = { {"maxbw", do_extract_maxbw}, {"priority", do_extract_priority} }; #define DLADM_MAX_RSRC_PROP (sizeof (rsrc_prop_table) / \ sizeof (resource_prop_t)) static dladm_status_t flow_proplist_check(dladm_arg_list_t *); dladm_status_t dladm_set_flowprop(const char *flow, const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags, char **errprop) { dladm_status_t status = DLADM_STATUS_BADARG; if (flow == NULL || (prop_val == NULL && val_cnt > 0) || (prop_val != NULL && val_cnt == 0) || flags == 0) return (DLADM_STATUS_BADARG); if ((flags & DLADM_OPT_ACTIVE) != 0) { status = i_dladm_set_prop_temp(flow, prop_name, prop_val, val_cnt, flags, errprop, &prop_tbl); if (status == DLADM_STATUS_TEMPONLY && (flags & DLADM_OPT_PERSIST) != 0) return (DLADM_STATUS_TEMPONLY); if (status != DLADM_STATUS_OK) return (status); } if ((flags & DLADM_OPT_PERSIST) != 0) { if (i_dladm_is_prop_temponly(prop_name, errprop, &prop_tbl)) return (DLADM_STATUS_TEMPONLY); status = i_dladm_set_flowprop_db(flow, prop_name, prop_val, val_cnt); } return (status); } dladm_status_t dladm_walk_flowprop(int (*func)(void *, const char *), const char *flow, void *arg) { int i; if (flow == NULL || func == NULL) return (DLADM_STATUS_BADARG); /* Then show data-flow properties if there are any */ for (i = 0; i < DLADM_MAX_FLOWPROPS; i++) { if (func(arg, prop_table[i].pd_name) != DLADM_WALK_CONTINUE) break; } return (DLADM_STATUS_OK); } dladm_status_t dladm_get_flowprop(const char *flow, uint32_t type, const char *prop_name, char **prop_val, uint_t *val_cntp) { dladm_status_t status; if (flow == NULL || prop_name == NULL || prop_val == NULL || val_cntp == NULL || *val_cntp == 0) return (DLADM_STATUS_BADARG); if (type == DLADM_PROP_VAL_PERSISTENT) { if (i_dladm_is_prop_temponly(prop_name, NULL, &prop_tbl)) return (DLADM_STATUS_TEMPONLY); return (i_dladm_get_flowprop_db(flow, prop_name, prop_val, val_cntp)); } status = i_dladm_get_prop_temp(flow, type, prop_name, prop_val, val_cntp, &prop_tbl); if (status != DLADM_STATUS_NOTFOUND) return (status); return (DLADM_STATUS_BADARG); } #define FLOWPROP_RW_DB(statep, writeop) \ (i_dladm_rw_db("/etc/dladm/flowprop.conf", \ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, process_prop_db, \ (statep), (writeop))) static dladm_status_t i_dladm_set_flowprop_db(const char *flow, const char *prop_name, char **prop_val, uint_t val_cnt) { prop_db_state_t state; state.ls_op = process_prop_set; state.ls_name = flow; state.ls_propname = prop_name; state.ls_propval = prop_val; state.ls_valcntp = &val_cnt; state.ls_initop = NULL; return (FLOWPROP_RW_DB(&state, B_TRUE)); } static dladm_status_t i_dladm_get_flowprop_db(const char *flow, const char *prop_name, char **prop_val, uint_t *val_cntp) { prop_db_state_t state; state.ls_op = process_prop_get; state.ls_name = flow; state.ls_propname = prop_name; state.ls_propval = prop_val; state.ls_valcntp = val_cntp; state.ls_initop = NULL; return (FLOWPROP_RW_DB(&state, B_FALSE)); } dladm_status_t i_dladm_init_flowprop_db(void) { prop_db_state_t state; state.ls_op = process_prop_init; state.ls_name = NULL; state.ls_propname = NULL; state.ls_propval = NULL; state.ls_valcntp = NULL; state.ls_initop = dladm_set_flowprop; return (FLOWPROP_RW_DB(&state, B_FALSE)); } #define MIN_INFO_SIZE (4 * 1024) dladm_status_t dladm_flow_info(const char *flow, dladm_flow_attr_t *attr) { dld_ioc_walkflow_t *ioc; int bufsize, fd; dld_flowinfo_t *flowinfo; if ((flow == NULL) || (attr == NULL)) return (DLADM_STATUS_BADARG); if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) return (dladm_errno2status(errno)); bufsize = MIN_INFO_SIZE; if ((ioc = calloc(1, bufsize)) == NULL) { (void) close(fd); return (dladm_errno2status(errno)); } (void) strlcpy(ioc->wf_name, flow, sizeof (ioc->wf_name)); ioc->wf_len = bufsize - sizeof (*ioc); while (ioctl(fd, DLDIOC_WALKFLOW, ioc) < 0) { if (errno == ENOSPC) { bufsize *= 2; ioc = realloc(ioc, bufsize); if (ioc != NULL) { (void) strlcpy(ioc->wf_name, flow, MAXNAMELEN); ioc->wf_len = bufsize - sizeof (*ioc); continue; } } free(ioc); (void) close(fd); return (dladm_errno2status(errno)); } bzero(attr, sizeof (*attr)); flowinfo = (dld_flowinfo_t *)(void *)(ioc + 1); attr->fa_linkid = flowinfo->fi_linkid; bcopy(&flowinfo->fi_flowname, &attr->fa_flowname, sizeof (attr->fa_flowname)); bcopy(&flowinfo->fi_flow_desc, &attr->fa_flow_desc, sizeof (attr->fa_flow_desc)); bcopy(&flowinfo->fi_resource_props, &attr->fa_resource_props, sizeof (attr->fa_resource_props)); free(ioc); (void) close(fd); return (DLADM_STATUS_OK); } /* ARGSUSED */ static dladm_status_t do_get_maxbw(const char *flow, char **prop_val, uint_t *val_cnt) { mac_resource_props_t *mrp; char buf[DLADM_STRSIZE]; dladm_flow_attr_t fa; dladm_status_t status; status = dladm_flow_info(flow, &fa); if (status != DLADM_STATUS_OK) return (status); mrp = &(fa.fa_resource_props); *val_cnt = 1; if (mrp->mrp_mask & MRP_MAXBW) { (void) snprintf(prop_val[0], DLADM_STRSIZE, "%s", dladm_bw2str(mrp->mrp_maxbw, buf)); } else { return (DLADM_STATUS_NOTSUP); } return (DLADM_STATUS_OK); } /* ARGSUSED */ static dladm_status_t do_set_maxbw(const char *flow, val_desc_t *vdp, uint_t val_cnt) { dld_ioc_modifyflow_t attr; int fd; mac_resource_props_t mrp; void *val; if (val_cnt != 1) return (DLADM_STATUS_BADVALCNT); bzero(&mrp, sizeof (mrp)); if (vdp != NULL && (val = (void *)vdp->vd_val) != NULL) { bcopy(val, &mrp.mrp_maxbw, sizeof (int64_t)); free(val); } else { mrp.mrp_maxbw = MRP_MAXBW_RESETVAL; } mrp.mrp_mask = MRP_MAXBW; bzero(&attr, sizeof (attr)); (void) strlcpy(attr.mf_name, flow, sizeof (attr.mf_name)); bcopy(&mrp, &attr.mf_resource_props, sizeof (mac_resource_props_t)); fd = open(DLD_CONTROL_DEV, O_RDWR); if (fd < 0) { return (dladm_errno2status(errno)); } if (ioctl(fd, DLDIOC_MODIFYFLOW, &attr) < 0) { (void) close(fd); return (dladm_errno2status(errno)); } (void) close(fd); return (DLADM_STATUS_OK); } /* ARGSUSED */ static dladm_status_t do_check_maxbw(fprop_desc_t *pdp, char **prop_val, uint_t val_cnt, val_desc_t **vdpp) { uint64_t *maxbw; val_desc_t *vdp = NULL; dladm_status_t status = DLADM_STATUS_OK; if (val_cnt != 1) return (DLADM_STATUS_BADVALCNT); maxbw = malloc(sizeof (uint64_t)); if (maxbw == NULL) return (DLADM_STATUS_NOMEM); status = dladm_str2bw(*prop_val, maxbw); if (status != DLADM_STATUS_OK) { free(maxbw); return (status); } if ((*maxbw < MRP_MAXBW_MINVAL) && (*maxbw != 0)) { free(maxbw); return (DLADM_STATUS_MINMAXBW); } vdp = malloc(sizeof (val_desc_t)); if (vdp == NULL) { free(maxbw); return (DLADM_STATUS_NOMEM); } vdp->vd_val = (uintptr_t)maxbw; *vdpp = vdp; return (DLADM_STATUS_OK); } /* ARGSUSED */ static dladm_status_t do_get_priority(const char *flow, char **prop_val, uint_t *val_cnt) { mac_resource_props_t *mrp; char buf[DLADM_STRSIZE]; dladm_flow_attr_t fa; dladm_status_t status; bzero(&fa, sizeof (dladm_flow_attr_t)); status = dladm_flow_info(flow, &fa); if (status != DLADM_STATUS_OK) return (status); mrp = &(fa.fa_resource_props); *val_cnt = 1; if (mrp->mrp_mask & MRP_PRIORITY) { (void) snprintf(prop_val[0], DLADM_STRSIZE, "%s", dladm_pri2str(mrp->mrp_priority, buf)); } else { return (DLADM_STATUS_NOTSUP); } return (DLADM_STATUS_OK); } /* ARGSUSED */ static dladm_status_t do_set_priority(const char *flow, val_desc_t *vdp, uint_t val_cnt) { dld_ioc_modifyflow_t attr; int fd; mac_resource_props_t mrp; void *val; if (val_cnt != 1) return (DLADM_STATUS_BADVALCNT); bzero(&mrp, sizeof (mrp)); if (vdp != NULL && (val = (void *)vdp->vd_val) != NULL) { bcopy(val, &mrp.mrp_priority, sizeof (mac_priority_level_t)); free(val); } else { mrp.mrp_priority = MPL_RESET; } mrp.mrp_mask = MRP_PRIORITY; bzero(&attr, sizeof (attr)); (void) strlcpy(attr.mf_name, flow, sizeof (attr.mf_name)); bcopy(&mrp, &attr.mf_resource_props, sizeof (mac_resource_props_t)); fd = open(DLD_CONTROL_DEV, O_RDWR); if (fd < 0) { return (dladm_errno2status(errno)); } if (ioctl(fd, DLDIOC_MODIFYFLOW, &attr) < 0) { (void) close(fd); return (dladm_errno2status(errno)); } (void) close(fd); return (DLADM_STATUS_OK); } /* ARGSUSED */ static dladm_status_t do_check_priority(fprop_desc_t *pdp, char **prop_val, uint_t val_cnt, val_desc_t **vdpp) { mac_priority_level_t *pri; val_desc_t *vdp = NULL; dladm_status_t status = DLADM_STATUS_OK; if (val_cnt != 1) return (DLADM_STATUS_BADVALCNT); pri = malloc(sizeof (mac_priority_level_t)); if (pri == NULL) return (DLADM_STATUS_NOMEM); status = dladm_str2pri(*prop_val, pri); if (status != DLADM_STATUS_OK) { free(pri); return (status); } if (*pri == -1) { free(pri); return (DLADM_STATUS_BADVAL); } vdp = malloc(sizeof (val_desc_t)); if (vdp == NULL) { free(pri); return (DLADM_STATUS_NOMEM); } vdp->vd_val = (uintptr_t)pri; *vdpp = vdp; return (DLADM_STATUS_OK); } static dladm_status_t flow_proplist_check(dladm_arg_list_t *proplist) { int i, j; boolean_t matched; for (i = 0; i < proplist->al_count; i++) { matched = B_FALSE; for (j = 0; j < DLADM_MAX_FLOWPROPS; j++) { if (strcmp(proplist->al_info[i].ai_name, prop_table[j].pd_name) == 0) matched = B_TRUE; } if (!matched) return (DLADM_STATUS_BADPROP); } return (DLADM_STATUS_OK); } dladm_status_t dladm_parse_flow_props(char *str, dladm_arg_list_t **listp, boolean_t novalues) { dladm_status_t status; status = dladm_parse_args(str, listp, novalues); if (status != DLADM_STATUS_OK) return (status); status = flow_proplist_check(*listp); if (status != DLADM_STATUS_OK) { dladm_free_props(*listp); return (status); } return (DLADM_STATUS_OK); } /* * Retrieve the named property from a proplist, check the value and * convert to a kernel structure. */ static dladm_status_t i_dladm_flow_proplist_extract_one(dladm_arg_list_t *proplist, const char *name, void *val) { dladm_status_t status; dladm_arg_info_t *aip = NULL; int i, j; /* Find named property in proplist */ for (i = 0; i < proplist->al_count; i++) { aip = &proplist->al_info[i]; if (strcasecmp(aip->ai_name, name) == 0) break; } /* Property not in list */ if (i == proplist->al_count) return (DLADM_STATUS_OK); for (i = 0; i < DLADM_MAX_FLOWPROPS; i++) { fprop_desc_t *pdp = &prop_table[i]; val_desc_t *vdp; vdp = malloc(sizeof (val_desc_t) * aip->ai_count); if (vdp == NULL) return (DLADM_STATUS_NOMEM); if (strcasecmp(aip->ai_name, pdp->pd_name) != 0) continue; if (aip->ai_val == NULL) return (DLADM_STATUS_BADARG); /* Check property value */ if (pdp->pd_check != NULL) { status = pdp->pd_check(pdp, aip->ai_val, aip->ai_count, &vdp); } else { status = DLADM_STATUS_BADARG; } if (status != DLADM_STATUS_OK) return (status); for (j = 0; j < DLADM_MAX_RSRC_PROP; j++) { resource_prop_t *rpp = &rsrc_prop_table[j]; if (strcasecmp(aip->ai_name, rpp->rp_name) != 0) continue; /* Extract kernel structure */ if (rpp->rp_extract != NULL) { status = rpp->rp_extract(vdp, val, aip->ai_count); } else { status = DLADM_STATUS_BADARG; } break; } if (status != DLADM_STATUS_OK) return (status); break; } return (status); } /* * Extract properties from a proplist and convert to mac_resource_props_t. */ dladm_status_t dladm_flow_proplist_extract(dladm_arg_list_t *proplist, mac_resource_props_t *mrp) { dladm_status_t status = DLADM_STATUS_OK; status = i_dladm_flow_proplist_extract_one(proplist, "maxbw", mrp); if (status != DLADM_STATUS_OK) return (status); status = i_dladm_flow_proplist_extract_one(proplist, "priority", mrp); if (status != DLADM_STATUS_OK) return (status); return (status); } dladm_status_t i_dladm_set_flow_proplist_db(char *flow, dladm_arg_list_t *proplist) { dladm_status_t status, ssave = DLADM_STATUS_OK; dladm_arg_info_t ai; int i; for (i = 0; i < proplist->al_count; i++) { ai = proplist->al_info[i]; status = i_dladm_set_flowprop_db(flow, ai.ai_name, ai.ai_val, ai.ai_count); if (status != DLADM_STATUS_OK) ssave = status; } return (ssave); }