summaryrefslogtreecommitdiff
path: root/usr/src/lib/libdladm/common/flowprop.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libdladm/common/flowprop.c')
-rw-r--r--usr/src/lib/libdladm/common/flowprop.c611
1 files changed, 611 insertions, 0 deletions
diff --git a/usr/src/lib/libdladm/common/flowprop.c b/usr/src/lib/libdladm/common/flowprop.c
new file mode 100644
index 0000000000..a2125a9d33
--- /dev/null
+++ b/usr/src/lib/libdladm/common/flowprop.c
@@ -0,0 +1,611 @@
+/*
+ * 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 <stdlib.h>
+#include <strings.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/dld.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <libdevinfo.h>
+#include <libdladm_impl.h>
+#include <libdlflow.h>
+#include <libdlflow_impl.h>
+#include <libintl.h>
+
+#include <dlfcn.h>
+#include <link.h>
+
+/*
+ * 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);
+}