Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <stdlib.h>
     27 #include <strings.h>
     28 #include <errno.h>
     29 #include <ctype.h>
     30 #include <sys/types.h>
     31 #include <sys/stat.h>
     32 #include <sys/dld.h>
     33 #include <sys/dld_ioc.h>
     34 #include <fcntl.h>
     35 #include <unistd.h>
     36 #include <libdevinfo.h>
     37 #include <libdladm_impl.h>
     38 #include <libdlflow.h>
     39 #include <libdlflow_impl.h>
     40 #include <libintl.h>
     41 
     42 #include <dlfcn.h>
     43 #include <link.h>
     44 
     45 /*
     46  * XXX duplicate define
     47  */
     48 #define	DLADM_PROP_VAL_MAX	32
     49 
     50 static dladm_status_t	i_dladm_set_flowprop_db(dladm_handle_t, const char *,
     51 			    const char *, char **, uint_t);
     52 static dladm_status_t	i_dladm_get_flowprop_db(dladm_handle_t, const char *,
     53 			    const char *, char **, uint_t *);
     54 
     55 static fpd_getf_t	do_get_maxbw;
     56 static fpd_setf_t	do_set_maxbw;
     57 static fpd_checkf_t	do_check_maxbw;
     58 
     59 static fpd_getf_t	do_get_priority;
     60 static fpd_setf_t	do_set_priority;
     61 static fpd_checkf_t	do_check_priority;
     62 
     63 static fprop_desc_t	prop_table[] = {
     64 	{ "maxbw",	{ "", NULL }, NULL, 0, B_FALSE,
     65 	    do_set_maxbw, NULL,
     66 	    do_get_maxbw, do_check_maxbw},
     67 	{ "priority",	{ "", NULL }, NULL, 0, B_FALSE,
     68 	    do_set_priority, NULL,
     69 	    do_get_priority, do_check_priority}
     70 };
     71 
     72 #define	DLADM_MAX_FLOWPROPS	(sizeof (prop_table) / sizeof (fprop_desc_t))
     73 
     74 static prop_table_t	prop_tbl = {
     75 	prop_table,
     76 	DLADM_MAX_FLOWPROPS
     77 };
     78 
     79 static resource_prop_t rsrc_prop_table[] = {
     80 	{"maxbw",	do_extract_maxbw},
     81 	{"priority",	do_extract_priority}
     82 };
     83 #define	DLADM_MAX_RSRC_PROP (sizeof (rsrc_prop_table) / \
     84 	sizeof (resource_prop_t))
     85 
     86 static dladm_status_t	flow_proplist_check(dladm_arg_list_t *);
     87 
     88 dladm_status_t
     89 dladm_set_flowprop(dladm_handle_t handle, const char *flow,
     90     const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags,
     91     char **errprop)
     92 {
     93 	dladm_status_t		status = DLADM_STATUS_BADARG;
     94 
     95 	if (flow == NULL || (prop_val == NULL && val_cnt > 0) ||
     96 	    (prop_val != NULL && val_cnt == 0) || flags == 0)
     97 		return (DLADM_STATUS_BADARG);
     98 
     99 	if ((flags & DLADM_OPT_ACTIVE) != 0) {
    100 		status = i_dladm_set_prop_temp(handle, flow, prop_name,
    101 		    prop_val, val_cnt, flags, errprop, &prop_tbl);
    102 		if (status == DLADM_STATUS_TEMPONLY &&
    103 		    (flags & DLADM_OPT_PERSIST) != 0)
    104 			return (DLADM_STATUS_TEMPONLY);
    105 		if (status != DLADM_STATUS_OK)
    106 			return (status);
    107 	}
    108 	if ((flags & DLADM_OPT_PERSIST) != 0) {
    109 		if (i_dladm_is_prop_temponly(prop_name, errprop, &prop_tbl))
    110 			return (DLADM_STATUS_TEMPONLY);
    111 
    112 		status = i_dladm_set_flowprop_db(handle, flow, prop_name,
    113 		    prop_val, val_cnt);
    114 	}
    115 	return (status);
    116 }
    117 
    118 dladm_status_t
    119 dladm_walk_flowprop(int (*func)(void *, const char *), const char *flow,
    120     void *arg)
    121 {
    122 	int	i;
    123 
    124 	if (flow == NULL || func == NULL)
    125 		return (DLADM_STATUS_BADARG);
    126 
    127 	/* Then show data-flow properties if there are any */
    128 	for (i = 0; i < DLADM_MAX_FLOWPROPS; i++) {
    129 		if (func(arg, prop_table[i].pd_name) != DLADM_WALK_CONTINUE)
    130 			break;
    131 	}
    132 	return (DLADM_STATUS_OK);
    133 }
    134 
    135 dladm_status_t
    136 dladm_get_flowprop(dladm_handle_t handle, const char *flow, uint32_t type,
    137     const char *prop_name, char **prop_val, uint_t *val_cntp)
    138 {
    139 	dladm_status_t status;
    140 
    141 	if (flow == NULL || prop_name == NULL || prop_val == NULL ||
    142 	    val_cntp == NULL || *val_cntp == 0)
    143 		return (DLADM_STATUS_BADARG);
    144 
    145 	if (type == DLADM_PROP_VAL_PERSISTENT) {
    146 		if (i_dladm_is_prop_temponly(prop_name, NULL, &prop_tbl))
    147 			return (DLADM_STATUS_TEMPONLY);
    148 		return (i_dladm_get_flowprop_db(handle, flow, prop_name,
    149 		    prop_val, val_cntp));
    150 	}
    151 
    152 	status = i_dladm_get_prop_temp(handle, flow, type, prop_name,
    153 	    prop_val, val_cntp, &prop_tbl);
    154 	if (status != DLADM_STATUS_NOTFOUND)
    155 		return (status);
    156 
    157 	return (DLADM_STATUS_BADARG);
    158 }
    159 
    160 #define	FLOWPROP_RW_DB(handle, statep, writeop)			\
    161 	(i_dladm_rw_db(handle, "/etc/dladm/flowprop.conf",	\
    162 	S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, process_prop_db, \
    163 	(statep), (writeop)))
    164 
    165 static dladm_status_t
    166 i_dladm_set_flowprop_db(dladm_handle_t handle, const char *flow,
    167     const char *prop_name, char **prop_val, uint_t val_cnt)
    168 {
    169 	prop_db_state_t	state;
    170 
    171 	state.ls_op = process_prop_set;
    172 	state.ls_name = flow;
    173 	state.ls_propname = prop_name;
    174 	state.ls_propval = prop_val;
    175 	state.ls_valcntp = &val_cnt;
    176 	state.ls_initop = NULL;
    177 
    178 	return (FLOWPROP_RW_DB(handle, &state, B_TRUE));
    179 }
    180 
    181 static dladm_status_t
    182 i_dladm_get_flowprop_db(dladm_handle_t handle, const char *flow,
    183     const char *prop_name, char **prop_val, uint_t *val_cntp)
    184 {
    185 	prop_db_state_t	state;
    186 
    187 	state.ls_op = process_prop_get;
    188 	state.ls_name = flow;
    189 	state.ls_propname = prop_name;
    190 	state.ls_propval = prop_val;
    191 	state.ls_valcntp = val_cntp;
    192 	state.ls_initop = NULL;
    193 
    194 	return (FLOWPROP_RW_DB(handle, &state, B_FALSE));
    195 }
    196 
    197 dladm_status_t
    198 i_dladm_init_flowprop_db(dladm_handle_t handle)
    199 {
    200 	prop_db_state_t	state;
    201 
    202 	state.ls_op = process_prop_init;
    203 	state.ls_name = NULL;
    204 	state.ls_propname = NULL;
    205 	state.ls_propval = NULL;
    206 	state.ls_valcntp = NULL;
    207 	state.ls_initop = dladm_set_flowprop;
    208 
    209 	return (FLOWPROP_RW_DB(handle, &state, B_FALSE));
    210 }
    211 
    212 #define	MIN_INFO_SIZE (4 * 1024)
    213 
    214 dladm_status_t
    215 dladm_flow_info(dladm_handle_t handle, const char *flow,
    216     dladm_flow_attr_t *attr)
    217 {
    218 	dld_ioc_walkflow_t	*ioc;
    219 	int			bufsize;
    220 	dld_flowinfo_t		*flowinfo;
    221 
    222 	if ((flow == NULL) || (attr == NULL))
    223 		return (DLADM_STATUS_BADARG);
    224 
    225 	bufsize = MIN_INFO_SIZE;
    226 	if ((ioc = calloc(1, bufsize)) == NULL)
    227 		return (dladm_errno2status(errno));
    228 
    229 	(void) strlcpy(ioc->wf_name, flow, sizeof (ioc->wf_name));
    230 	ioc->wf_len = bufsize - sizeof (*ioc);
    231 
    232 	while (ioctl(dladm_dld_fd(handle), DLDIOC_WALKFLOW, ioc) < 0) {
    233 		if (errno == ENOSPC) {
    234 			bufsize *= 2;
    235 			ioc = realloc(ioc, bufsize);
    236 			if (ioc != NULL) {
    237 				(void) strlcpy(ioc->wf_name, flow,
    238 				    MAXFLOWNAMELEN);
    239 				ioc->wf_len = bufsize - sizeof (*ioc);
    240 				continue;
    241 			}
    242 		}
    243 		free(ioc);
    244 		return (dladm_errno2status(errno));
    245 	}
    246 
    247 	bzero(attr, sizeof (*attr));
    248 
    249 	flowinfo = (dld_flowinfo_t *)(void *)(ioc + 1);
    250 
    251 	attr->fa_linkid = flowinfo->fi_linkid;
    252 	bcopy(&flowinfo->fi_flowname, &attr->fa_flowname,
    253 	    sizeof (attr->fa_flowname));
    254 	bcopy(&flowinfo->fi_flow_desc, &attr->fa_flow_desc,
    255 	    sizeof (attr->fa_flow_desc));
    256 	bcopy(&flowinfo->fi_resource_props, &attr->fa_resource_props,
    257 	    sizeof (attr->fa_resource_props));
    258 
    259 	free(ioc);
    260 	return (DLADM_STATUS_OK);
    261 }
    262 
    263 /* ARGSUSED */
    264 static dladm_status_t
    265 do_get_maxbw(dladm_handle_t handle, const char *flow, char **prop_val,
    266     uint_t *val_cnt)
    267 {
    268 	mac_resource_props_t	*mrp;
    269 	char 			buf[DLADM_STRSIZE];
    270 	dladm_flow_attr_t	fa;
    271 	dladm_status_t		status;
    272 
    273 	status = dladm_flow_info(handle, flow, &fa);
    274 	if (status != DLADM_STATUS_OK)
    275 		return (status);
    276 	mrp = &(fa.fa_resource_props);
    277 
    278 	*val_cnt = 1;
    279 	if (mrp->mrp_mask & MRP_MAXBW) {
    280 		(void) snprintf(prop_val[0], DLADM_STRSIZE, "%s",
    281 		    dladm_bw2str(mrp->mrp_maxbw, buf));
    282 	} else {
    283 		return (DLADM_STATUS_NOTSUP);
    284 	}
    285 	return (DLADM_STATUS_OK);
    286 }
    287 
    288 /* ARGSUSED */
    289 static dladm_status_t
    290 do_set_maxbw(dladm_handle_t handle, const char *flow, val_desc_t *vdp,
    291     uint_t val_cnt)
    292 {
    293 	dld_ioc_modifyflow_t	attr;
    294 	mac_resource_props_t	mrp;
    295 	void			*val;
    296 
    297 	if (val_cnt != 1)
    298 		return (DLADM_STATUS_BADVALCNT);
    299 
    300 	bzero(&mrp, sizeof (mrp));
    301 	if (vdp != NULL && (val = (void *)vdp->vd_val) != NULL) {
    302 		bcopy(val, &mrp.mrp_maxbw, sizeof (int64_t));
    303 		free(val);
    304 	} else {
    305 		mrp.mrp_maxbw = MRP_MAXBW_RESETVAL;
    306 	}
    307 	mrp.mrp_mask = MRP_MAXBW;
    308 
    309 	bzero(&attr, sizeof (attr));
    310 	(void) strlcpy(attr.mf_name, flow, sizeof (attr.mf_name));
    311 	bcopy(&mrp, &attr.mf_resource_props, sizeof (mac_resource_props_t));
    312 
    313 	if (ioctl(dladm_dld_fd(handle), DLDIOC_MODIFYFLOW, &attr) < 0)
    314 		return (dladm_errno2status(errno));
    315 
    316 	return (DLADM_STATUS_OK);
    317 }
    318 
    319 /* ARGSUSED */
    320 static dladm_status_t
    321 do_check_maxbw(fprop_desc_t *pdp, char **prop_val, uint_t val_cnt,
    322     val_desc_t **vdpp)
    323 {
    324 	uint64_t	*maxbw;
    325 	val_desc_t	*vdp = NULL;
    326 	dladm_status_t	status = DLADM_STATUS_OK;
    327 
    328 	if (val_cnt != 1)
    329 		return (DLADM_STATUS_BADVALCNT);
    330 
    331 	maxbw = malloc(sizeof (uint64_t));
    332 	if (maxbw == NULL)
    333 		return (DLADM_STATUS_NOMEM);
    334 
    335 	status = dladm_str2bw(*prop_val, maxbw);
    336 	if (status != DLADM_STATUS_OK) {
    337 		free(maxbw);
    338 		return (status);
    339 	}
    340 
    341 	if ((*maxbw < MRP_MAXBW_MINVAL) && (*maxbw != 0)) {
    342 		free(maxbw);
    343 		return (DLADM_STATUS_MINMAXBW);
    344 	}
    345 
    346 	vdp = malloc(sizeof (val_desc_t));
    347 	if (vdp == NULL) {
    348 		free(maxbw);
    349 		return (DLADM_STATUS_NOMEM);
    350 	}
    351 
    352 	vdp->vd_val = (uintptr_t)maxbw;
    353 	*vdpp = vdp;
    354 	return (DLADM_STATUS_OK);
    355 }
    356 
    357 /* ARGSUSED */
    358 static dladm_status_t
    359 do_get_priority(dladm_handle_t handle, const char *flow, char **prop_val,
    360     uint_t *val_cnt)
    361 {
    362 	mac_resource_props_t	*mrp;
    363 	char 			buf[DLADM_STRSIZE];
    364 	dladm_flow_attr_t	fa;
    365 	dladm_status_t		status;
    366 
    367 	bzero(&fa, sizeof (dladm_flow_attr_t));
    368 	status = dladm_flow_info(handle, flow, &fa);
    369 	if (status != DLADM_STATUS_OK)
    370 		return (status);
    371 	mrp = &(fa.fa_resource_props);
    372 
    373 	*val_cnt = 1;
    374 	if (mrp->mrp_mask & MRP_PRIORITY) {
    375 		(void) snprintf(prop_val[0], DLADM_STRSIZE, "%s",
    376 		    dladm_pri2str(mrp->mrp_priority, buf));
    377 	} else {
    378 		return (DLADM_STATUS_NOTSUP);
    379 	}
    380 	return (DLADM_STATUS_OK);
    381 }
    382 
    383 /* ARGSUSED */
    384 static dladm_status_t
    385 do_set_priority(dladm_handle_t handle, const char *flow, val_desc_t *vdp,
    386     uint_t val_cnt)
    387 {
    388 	dld_ioc_modifyflow_t	attr;
    389 	mac_resource_props_t	mrp;
    390 	void			*val;
    391 
    392 	if (val_cnt != 1)
    393 		return (DLADM_STATUS_BADVALCNT);
    394 
    395 	bzero(&mrp, sizeof (mrp));
    396 	if (vdp != NULL && (val = (void *)vdp->vd_val) != NULL) {
    397 		bcopy(val, &mrp.mrp_priority, sizeof (mac_priority_level_t));
    398 		free(val);
    399 	} else {
    400 		mrp.mrp_priority = MPL_RESET;
    401 	}
    402 	mrp.mrp_mask = MRP_PRIORITY;
    403 
    404 	bzero(&attr, sizeof (attr));
    405 	(void) strlcpy(attr.mf_name, flow, sizeof (attr.mf_name));
    406 	bcopy(&mrp, &attr.mf_resource_props, sizeof (mac_resource_props_t));
    407 
    408 	if (ioctl(dladm_dld_fd(handle), DLDIOC_MODIFYFLOW, &attr) < 0)
    409 		return (dladm_errno2status(errno));
    410 
    411 	return (DLADM_STATUS_OK);
    412 }
    413 
    414 /* ARGSUSED */
    415 static dladm_status_t
    416 do_check_priority(fprop_desc_t *pdp, char **prop_val, uint_t val_cnt,
    417     val_desc_t **vdpp)
    418 {
    419 	mac_priority_level_t	*pri;
    420 	val_desc_t	*vdp = NULL;
    421 	dladm_status_t	status = DLADM_STATUS_OK;
    422 
    423 	if (val_cnt != 1)
    424 		return (DLADM_STATUS_BADVALCNT);
    425 
    426 	pri = malloc(sizeof (mac_priority_level_t));
    427 	if (pri == NULL)
    428 		return (DLADM_STATUS_NOMEM);
    429 
    430 	status = dladm_str2pri(*prop_val, pri);
    431 	if (status != DLADM_STATUS_OK) {
    432 		free(pri);
    433 		return (status);
    434 	}
    435 
    436 	if (*pri == -1) {
    437 		free(pri);
    438 		return (DLADM_STATUS_BADVAL);
    439 	}
    440 
    441 	vdp = malloc(sizeof (val_desc_t));
    442 	if (vdp == NULL) {
    443 		free(pri);
    444 		return (DLADM_STATUS_NOMEM);
    445 	}
    446 
    447 	vdp->vd_val = (uintptr_t)pri;
    448 	*vdpp = vdp;
    449 	return (DLADM_STATUS_OK);
    450 }
    451 
    452 static dladm_status_t
    453 flow_proplist_check(dladm_arg_list_t *proplist)
    454 {
    455 	int		i, j;
    456 	boolean_t	matched;
    457 
    458 	for (i = 0; i < proplist->al_count; i++) {
    459 		matched = B_FALSE;
    460 		for (j = 0; j < DLADM_MAX_FLOWPROPS; j++) {
    461 			if (strcmp(proplist->al_info[i].ai_name,
    462 			    prop_table[j].pd_name) == 0)
    463 				matched = B_TRUE;
    464 			}
    465 		if (!matched)
    466 			return (DLADM_STATUS_BADPROP);
    467 	}
    468 	return (DLADM_STATUS_OK);
    469 
    470 }
    471 
    472 dladm_status_t
    473 dladm_parse_flow_props(char *str, dladm_arg_list_t **listp, boolean_t novalues)
    474 {
    475 	dladm_status_t	status;
    476 
    477 	status = dladm_parse_args(str, listp, novalues);
    478 	if (status != DLADM_STATUS_OK)
    479 		return (status);
    480 
    481 	if (*listp != NULL && (status = flow_proplist_check(*listp)
    482 	    != DLADM_STATUS_OK)) {
    483 		dladm_free_props(*listp);
    484 		return (status);
    485 	}
    486 
    487 	return (DLADM_STATUS_OK);
    488 }
    489 
    490 /*
    491  * Retrieve the named property from a proplist, check the value and
    492  * convert to a kernel structure.
    493  */
    494 static dladm_status_t
    495 i_dladm_flow_proplist_extract_one(dladm_arg_list_t *proplist,
    496     const char *name, void *arg)
    497 {
    498 	dladm_status_t		status;
    499 	dladm_arg_info_t	*aip = NULL;
    500 	int			i, j;
    501 
    502 	/* Find named property in proplist */
    503 	for (i = 0; i < proplist->al_count; i++) {
    504 		aip = &proplist->al_info[i];
    505 		if (strcasecmp(aip->ai_name, name) == 0)
    506 			break;
    507 	}
    508 
    509 	/* Property not in list */
    510 	if (i == proplist->al_count)
    511 		return (DLADM_STATUS_OK);
    512 
    513 	for (i = 0; i < DLADM_MAX_FLOWPROPS; i++) {
    514 		fprop_desc_t	*pdp = &prop_table[i];
    515 		val_desc_t	*vdp;
    516 
    517 		vdp = malloc(sizeof (val_desc_t) * aip->ai_count);
    518 		if (vdp == NULL)
    519 			return (DLADM_STATUS_NOMEM);
    520 
    521 		if (strcasecmp(aip->ai_name, pdp->pd_name) != 0)
    522 			continue;
    523 
    524 		if (aip->ai_val == NULL)
    525 			return (DLADM_STATUS_BADARG);
    526 
    527 		/* Check property value */
    528 		if (pdp->pd_check != NULL) {
    529 			status = pdp->pd_check(pdp, aip->ai_val,
    530 			    aip->ai_count, &vdp);
    531 		} else {
    532 			status = DLADM_STATUS_BADARG;
    533 		}
    534 
    535 		if (status != DLADM_STATUS_OK)
    536 			return (status);
    537 
    538 		for (j = 0; j < DLADM_MAX_RSRC_PROP; j++) {
    539 			resource_prop_t	*rpp = &rsrc_prop_table[j];
    540 
    541 			if (strcasecmp(aip->ai_name, rpp->rp_name) != 0)
    542 				continue;
    543 
    544 			/* Extract kernel structure */
    545 			if (rpp->rp_extract != NULL) {
    546 				status = rpp->rp_extract(vdp,
    547 				    aip->ai_count, arg);
    548 			} else {
    549 				status = DLADM_STATUS_BADARG;
    550 			}
    551 			break;
    552 		}
    553 
    554 		if (status != DLADM_STATUS_OK)
    555 			return (status);
    556 
    557 		break;
    558 	}
    559 	return (status);
    560 }
    561 
    562 /*
    563  * Extract properties from a proplist and convert to mac_resource_props_t.
    564  */
    565 dladm_status_t
    566 dladm_flow_proplist_extract(dladm_arg_list_t *proplist,
    567     mac_resource_props_t *mrp)
    568 {
    569 	dladm_status_t	status = DLADM_STATUS_OK;
    570 
    571 	status = i_dladm_flow_proplist_extract_one(proplist, "maxbw", mrp);
    572 	if (status != DLADM_STATUS_OK)
    573 		return (status);
    574 	status = i_dladm_flow_proplist_extract_one(proplist, "priority", mrp);
    575 	if (status != DLADM_STATUS_OK)
    576 		return (status);
    577 	return (status);
    578 }
    579 
    580 dladm_status_t
    581 i_dladm_set_flow_proplist_db(dladm_handle_t handle, char *flow,
    582     dladm_arg_list_t *proplist)
    583 {
    584 	dladm_status_t		status, ssave = DLADM_STATUS_OK;
    585 	dladm_arg_info_t	ai;
    586 	int			i;
    587 
    588 	for (i = 0; i < proplist->al_count; i++) {
    589 		ai = proplist->al_info[i];
    590 		status = i_dladm_set_flowprop_db(handle, flow, ai.ai_name,
    591 		    ai.ai_val, ai.ai_count);
    592 		if (status != DLADM_STATUS_OK)
    593 			ssave = status;
    594 	}
    595 	return (ssave);
    596 }
    597