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