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