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 *val) 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, val, 547 aip->ai_count); 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