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