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 2010 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", { "", MPL_RESET }, 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", extract_maxbw}, 81 {"priority", 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 391 if (val_cnt != 1) 392 return (DLADM_STATUS_BADVALCNT); 393 394 bzero(&mrp, sizeof (mrp)); 395 if (vdp != NULL) { 396 bcopy(&vdp->vd_val, &mrp.mrp_priority, 397 sizeof (mac_priority_level_t)); 398 } else { 399 mrp.mrp_priority = MPL_RESET; 400 } 401 mrp.mrp_mask = MRP_PRIORITY; 402 403 bzero(&attr, sizeof (attr)); 404 (void) strlcpy(attr.mf_name, flow, sizeof (attr.mf_name)); 405 bcopy(&mrp, &attr.mf_resource_props, sizeof (mac_resource_props_t)); 406 407 if (ioctl(dladm_dld_fd(handle), DLDIOC_MODIFYFLOW, &attr) < 0) 408 return (dladm_errno2status(errno)); 409 410 return (DLADM_STATUS_OK); 411 } 412 413 /* ARGSUSED */ 414 static dladm_status_t 415 do_check_priority(fprop_desc_t *pdp, char **prop_val, uint_t val_cnt, 416 val_desc_t **vdpp) 417 { 418 mac_priority_level_t pri; 419 val_desc_t *vdp = NULL; 420 dladm_status_t status = DLADM_STATUS_OK; 421 422 if (val_cnt != 1) 423 return (DLADM_STATUS_BADVALCNT); 424 425 status = dladm_str2pri(*prop_val, &pri); 426 if (status != DLADM_STATUS_OK) 427 return (status); 428 429 if (pri == -1) 430 return (DLADM_STATUS_BADVAL); 431 432 vdp = malloc(sizeof (val_desc_t)); 433 if (vdp == NULL) 434 return (DLADM_STATUS_NOMEM); 435 436 vdp->vd_val = (uint_t)pri; 437 *vdpp = vdp; 438 return (DLADM_STATUS_OK); 439 } 440 441 static dladm_status_t 442 flow_proplist_check(dladm_arg_list_t *proplist) 443 { 444 int i, j; 445 boolean_t matched; 446 447 for (i = 0; i < proplist->al_count; i++) { 448 matched = B_FALSE; 449 for (j = 0; j < DLADM_MAX_FLOWPROPS; j++) { 450 if (strcmp(proplist->al_info[i].ai_name, 451 prop_table[j].pd_name) == 0) 452 matched = B_TRUE; 453 } 454 if (!matched) 455 return (DLADM_STATUS_BADPROP); 456 } 457 return (DLADM_STATUS_OK); 458 459 } 460 461 dladm_status_t 462 dladm_parse_flow_props(char *str, dladm_arg_list_t **listp, boolean_t novalues) 463 { 464 dladm_status_t status; 465 466 status = dladm_parse_args(str, listp, novalues); 467 if (status != DLADM_STATUS_OK) 468 return (status); 469 470 if (*listp != NULL && (status = flow_proplist_check(*listp) 471 != DLADM_STATUS_OK)) { 472 dladm_free_props(*listp); 473 return (status); 474 } 475 476 return (DLADM_STATUS_OK); 477 } 478 479 /* 480 * Retrieve the named property from a proplist, check the value and 481 * convert to a kernel structure. 482 */ 483 static dladm_status_t 484 i_dladm_flow_proplist_extract_one(dladm_arg_list_t *proplist, 485 const char *name, void *arg) 486 { 487 dladm_status_t status; 488 dladm_arg_info_t *aip = NULL; 489 int i, j; 490 491 /* Find named property in proplist */ 492 for (i = 0; i < proplist->al_count; i++) { 493 aip = &proplist->al_info[i]; 494 if (strcasecmp(aip->ai_name, name) == 0) 495 break; 496 } 497 498 /* Property not in list */ 499 if (i == proplist->al_count) 500 return (DLADM_STATUS_OK); 501 502 for (i = 0; i < DLADM_MAX_FLOWPROPS; i++) { 503 fprop_desc_t *pdp = &prop_table[i]; 504 val_desc_t *vdp; 505 506 vdp = malloc(sizeof (val_desc_t) * aip->ai_count); 507 if (vdp == NULL) 508 return (DLADM_STATUS_NOMEM); 509 510 if (strcasecmp(aip->ai_name, pdp->pd_name) != 0) 511 continue; 512 513 if (aip->ai_val == NULL) 514 return (DLADM_STATUS_BADARG); 515 516 /* Check property value */ 517 if (pdp->pd_check != NULL) { 518 status = pdp->pd_check(pdp, aip->ai_val, 519 aip->ai_count, &vdp); 520 } else { 521 status = DLADM_STATUS_BADARG; 522 } 523 524 if (status != DLADM_STATUS_OK) 525 return (status); 526 527 for (j = 0; j < DLADM_MAX_RSRC_PROP; j++) { 528 resource_prop_t *rpp = &rsrc_prop_table[j]; 529 530 if (strcasecmp(aip->ai_name, rpp->rp_name) != 0) 531 continue; 532 533 /* Extract kernel structure */ 534 if (rpp->rp_extract != NULL) { 535 status = rpp->rp_extract(vdp, 536 aip->ai_count, arg); 537 } else { 538 status = DLADM_STATUS_BADARG; 539 } 540 break; 541 } 542 543 if (status != DLADM_STATUS_OK) 544 return (status); 545 546 break; 547 } 548 return (status); 549 } 550 551 /* 552 * Extract properties from a proplist and convert to mac_resource_props_t. 553 */ 554 dladm_status_t 555 dladm_flow_proplist_extract(dladm_arg_list_t *proplist, 556 mac_resource_props_t *mrp) 557 { 558 dladm_status_t status = DLADM_STATUS_OK; 559 560 status = i_dladm_flow_proplist_extract_one(proplist, "maxbw", mrp); 561 if (status != DLADM_STATUS_OK) 562 return (status); 563 status = i_dladm_flow_proplist_extract_one(proplist, "priority", mrp); 564 if (status != DLADM_STATUS_OK) 565 return (status); 566 return (status); 567 } 568 569 dladm_status_t 570 i_dladm_set_flow_proplist_db(dladm_handle_t handle, char *flow, 571 dladm_arg_list_t *proplist) 572 { 573 dladm_status_t status, ssave = DLADM_STATUS_OK; 574 dladm_arg_info_t ai; 575 int i; 576 577 for (i = 0; i < proplist->al_count; i++) { 578 ai = proplist->al_info[i]; 579 status = i_dladm_set_flowprop_db(handle, flow, ai.ai_name, 580 ai.ai_val, ai.ai_count); 581 if (status != DLADM_STATUS_OK) 582 ssave = status; 583 } 584 return (ssave); 585 } 586