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