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 <door.h> 27 #include <errno.h> 28 #include <assert.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <unistd.h> 32 #include <string.h> 33 #include <strings.h> 34 #include <sys/types.h> 35 #include <sys/stat.h> 36 #include <sys/aggr.h> 37 #include <fcntl.h> 38 #include <libdladm.h> 39 #include <libdladm_impl.h> 40 #include <libdllink.h> 41 #include <libdlmgmt.h> 42 43 /* 44 * Table of data type sizes indexed by dladm_datatype_t. 45 */ 46 static size_t dladm_datatype_size[] = { 47 0, /* DLADM_TYPE_STR, use strnlen() */ 48 sizeof (boolean_t), /* DLADM_TYPE_BOOLEAN */ 49 sizeof (uint64_t) /* DLADM_TYPE_UINT64 */ 50 }; 51 52 static dladm_status_t 53 dladm_door_call(dladm_handle_t handle, void *arg, size_t asize, void *rbuf, 54 size_t rsize) 55 { 56 door_arg_t darg; 57 int door_fd; 58 dladm_status_t status = DLADM_STATUS_OK; 59 60 darg.data_ptr = arg; 61 darg.data_size = asize; 62 darg.desc_ptr = NULL; 63 darg.desc_num = 0; 64 darg.rbuf = rbuf; 65 darg.rsize = rsize; 66 67 /* The door descriptor is opened if it isn't already */ 68 if ((status = dladm_door_fd(handle, &door_fd)) != DLADM_STATUS_OK) 69 return (status); 70 if (door_call(door_fd, &darg) == -1) 71 status = dladm_errno2status(errno); 72 if (status != DLADM_STATUS_OK) 73 return (status); 74 75 if (darg.rbuf != rbuf) { 76 /* 77 * The size of the input rbuf is not big enough so that 78 * the door allocate the rbuf itself. In this case, simply 79 * think something wrong with the door call. 80 */ 81 (void) munmap(darg.rbuf, darg.rsize); 82 return (DLADM_STATUS_TOOSMALL); 83 } 84 if (darg.rsize != rsize) 85 return (DLADM_STATUS_FAILED); 86 87 return (dladm_errno2status(((dlmgmt_retval_t *)rbuf)->lr_err)); 88 } 89 90 /* 91 * Allocate a new linkid with the given name. Return the new linkid. 92 */ 93 dladm_status_t 94 dladm_create_datalink_id(dladm_handle_t handle, const char *link, 95 datalink_class_t class, uint32_t media, uint32_t flags, 96 datalink_id_t *linkidp) 97 { 98 dlmgmt_door_createid_t createid; 99 dlmgmt_createid_retval_t retval; 100 uint32_t dlmgmt_flags; 101 dladm_status_t status; 102 103 if (link == NULL || class == DATALINK_CLASS_ALL || 104 !(flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST)) || 105 linkidp == NULL) { 106 return (DLADM_STATUS_BADARG); 107 } 108 109 dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0; 110 dlmgmt_flags |= (flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0; 111 112 (void) strlcpy(createid.ld_link, link, MAXLINKNAMELEN); 113 createid.ld_class = class; 114 createid.ld_media = media; 115 createid.ld_flags = dlmgmt_flags; 116 createid.ld_cmd = DLMGMT_CMD_CREATE_LINKID; 117 createid.ld_prefix = (flags & DLADM_OPT_PREFIX); 118 119 if ((status = dladm_door_call(handle, &createid, sizeof (createid), 120 &retval, sizeof (retval))) == DLADM_STATUS_OK) { 121 *linkidp = retval.lr_linkid; 122 } 123 return (status); 124 } 125 126 /* 127 * Destroy the given link ID. 128 */ 129 dladm_status_t 130 dladm_destroy_datalink_id(dladm_handle_t handle, datalink_id_t linkid, 131 uint32_t flags) 132 { 133 dlmgmt_door_destroyid_t destroyid; 134 dlmgmt_destroyid_retval_t retval; 135 uint32_t dlmgmt_flags; 136 137 dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0; 138 dlmgmt_flags |= ((flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0); 139 140 destroyid.ld_cmd = DLMGMT_CMD_DESTROY_LINKID; 141 destroyid.ld_linkid = linkid; 142 destroyid.ld_flags = dlmgmt_flags; 143 144 return (dladm_door_call(handle, &destroyid, sizeof (destroyid), &retval, 145 sizeof (retval))); 146 } 147 148 /* 149 * Remap a given link ID to a new name. 150 */ 151 dladm_status_t 152 dladm_remap_datalink_id(dladm_handle_t handle, datalink_id_t linkid, 153 const char *link) 154 { 155 dlmgmt_door_remapid_t remapid; 156 dlmgmt_remapid_retval_t retval; 157 158 remapid.ld_cmd = DLMGMT_CMD_REMAP_LINKID; 159 remapid.ld_linkid = linkid; 160 (void) strlcpy(remapid.ld_link, link, MAXLINKNAMELEN); 161 162 return (dladm_door_call(handle, &remapid, sizeof (remapid), &retval, 163 sizeof (retval))); 164 } 165 166 /* 167 * Make a given link ID active. 168 */ 169 dladm_status_t 170 dladm_up_datalink_id(dladm_handle_t handle, datalink_id_t linkid) 171 { 172 dlmgmt_door_upid_t upid; 173 dlmgmt_upid_retval_t retval; 174 175 upid.ld_cmd = DLMGMT_CMD_UP_LINKID; 176 upid.ld_linkid = linkid; 177 178 return (dladm_door_call(handle, &upid, sizeof (upid), &retval, 179 sizeof (retval))); 180 } 181 182 /* 183 * Create a new link with the given name. Return the new link's handle 184 */ 185 dladm_status_t 186 dladm_create_conf(dladm_handle_t handle, const char *link, datalink_id_t linkid, 187 datalink_class_t class, uint32_t media, dladm_conf_t *confp) 188 { 189 dlmgmt_door_createconf_t createconf; 190 dlmgmt_createconf_retval_t retval; 191 dladm_status_t status; 192 193 if (link == NULL || confp == NULL) 194 return (DLADM_STATUS_BADARG); 195 196 (void) strlcpy(createconf.ld_link, link, MAXLINKNAMELEN); 197 createconf.ld_class = class; 198 createconf.ld_media = media; 199 createconf.ld_linkid = linkid; 200 createconf.ld_cmd = DLMGMT_CMD_CREATECONF; 201 202 if ((status = dladm_door_call(handle, &createconf, sizeof (createconf), 203 &retval, sizeof (retval))) == DLADM_STATUS_OK) { 204 *confp = retval.lr_conf; 205 } 206 return (status); 207 } 208 209 /* 210 * An active physical link reported by the dlmgmtd daemon might not be active 211 * anymore as this link might be removed during system shutdown. Check its 212 * real status by calling dladm_phys_info(). 213 */ 214 dladm_status_t 215 i_dladm_phys_status(dladm_handle_t handle, datalink_id_t linkid, 216 uint32_t *flagsp) 217 { 218 dladm_phys_attr_t dpa; 219 dladm_status_t status; 220 221 assert((*flagsp) & DLMGMT_ACTIVE); 222 223 status = dladm_phys_info(handle, linkid, &dpa, DLADM_OPT_ACTIVE); 224 if (status == DLADM_STATUS_NOTFOUND) { 225 /* 226 * No active status, this link was removed. Update its status 227 * in the daemon and delete all active linkprops. 228 * 229 * Note that the operation could fail. If it does, return 230 * failure now since otherwise dladm_set_linkprop() might 231 * call back to i_dladm_phys_status() recursively. 232 */ 233 if ((status = dladm_destroy_datalink_id(handle, linkid, 234 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) 235 return (status); 236 237 (void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0, 238 DLADM_OPT_ACTIVE); 239 240 (*flagsp) &= ~DLMGMT_ACTIVE; 241 status = DLADM_STATUS_OK; 242 } 243 return (status); 244 } 245 246 /* 247 * Walk each entry in the data link configuration repository and 248 * call fn on the linkid and arg. 249 */ 250 dladm_status_t 251 dladm_walk_datalink_id(int (*fn)(dladm_handle_t, datalink_id_t, void *), 252 dladm_handle_t handle, void *argp, datalink_class_t class, 253 datalink_media_t dmedia, uint32_t flags) 254 { 255 dlmgmt_door_getnext_t getnext; 256 dlmgmt_getnext_retval_t retval; 257 uint32_t dlmgmt_flags; 258 datalink_id_t linkid = DATALINK_INVALID_LINKID; 259 dladm_status_t status = DLADM_STATUS_OK; 260 261 if (fn == NULL) 262 return (DLADM_STATUS_BADARG); 263 264 dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0; 265 dlmgmt_flags |= ((flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0); 266 267 getnext.ld_cmd = DLMGMT_CMD_GETNEXT; 268 getnext.ld_class = class; 269 getnext.ld_dmedia = dmedia; 270 getnext.ld_flags = dlmgmt_flags; 271 272 do { 273 getnext.ld_linkid = linkid; 274 if ((status = dladm_door_call(handle, &getnext, 275 sizeof (getnext), &retval, sizeof (retval))) != 276 DLADM_STATUS_OK) { 277 /* 278 * done with walking 279 */ 280 break; 281 } 282 283 linkid = retval.lr_linkid; 284 if ((retval.lr_class == DATALINK_CLASS_PHYS) && 285 (retval.lr_flags & DLMGMT_ACTIVE)) { 286 /* 287 * An active physical link reported by the dlmgmtd 288 * daemon might not be active anymore. Check its 289 * real status. 290 */ 291 if (i_dladm_phys_status(handle, linkid, 292 &retval.lr_flags) != DLADM_STATUS_OK) { 293 continue; 294 } 295 296 if (!(dlmgmt_flags & retval.lr_flags)) 297 continue; 298 } 299 300 if (fn(handle, linkid, argp) == DLADM_WALK_TERMINATE) 301 break; 302 } while (linkid != DATALINK_INVALID_LINKID); 303 304 return (status); 305 } 306 307 /* 308 * Get the link properties structure for the given link. 309 */ 310 dladm_status_t 311 dladm_read_conf(dladm_handle_t handle, datalink_id_t linkid, 312 dladm_conf_t *confp) 313 { 314 dlmgmt_door_readconf_t readconf; 315 dlmgmt_readconf_retval_t retval; 316 dladm_status_t status; 317 318 if (linkid == DATALINK_INVALID_LINKID || confp == NULL) 319 return (DLADM_STATUS_BADARG); 320 321 readconf.ld_linkid = linkid; 322 readconf.ld_cmd = DLMGMT_CMD_READCONF; 323 324 if ((status = dladm_door_call(handle, &readconf, sizeof (readconf), 325 &retval, sizeof (retval))) == DLADM_STATUS_OK) { 326 *confp = retval.lr_conf; 327 } 328 return (status); 329 } 330 331 /* 332 * Commit the given link to the data link configuration repository so 333 * that it will persist across reboots. 334 */ 335 dladm_status_t 336 dladm_write_conf(dladm_handle_t handle, dladm_conf_t conf) 337 { 338 dlmgmt_door_writeconf_t writeconf; 339 dlmgmt_writeconf_retval_t retval; 340 341 if (conf == DLADM_INVALID_CONF) 342 return (DLADM_STATUS_BADARG); 343 344 writeconf.ld_cmd = DLMGMT_CMD_WRITECONF; 345 writeconf.ld_conf = conf; 346 347 return (dladm_door_call(handle, &writeconf, sizeof (writeconf), &retval, 348 sizeof (retval))); 349 } 350 351 /* 352 * Given a link ID and a key, get the matching information from 353 * data link configuration repository. 354 */ 355 dladm_status_t 356 dladm_get_conf_field(dladm_handle_t handle, dladm_conf_t conf, const char *attr, 357 void *attrval, size_t attrsz) 358 { 359 dlmgmt_door_getattr_t getattr; 360 dlmgmt_getattr_retval_t retval; 361 dladm_status_t status; 362 363 if (conf == DLADM_INVALID_CONF || attrval == NULL || 364 attrsz == 0 || attr == NULL) { 365 return (DLADM_STATUS_BADARG); 366 } 367 368 getattr.ld_cmd = DLMGMT_CMD_GETATTR; 369 getattr.ld_conf = conf; 370 (void) strlcpy(getattr.ld_attr, attr, MAXLINKATTRLEN); 371 372 if ((status = dladm_door_call(handle, &getattr, sizeof (getattr), 373 &retval, sizeof (retval))) != DLADM_STATUS_OK) { 374 return (status); 375 } 376 377 if (retval.lr_attrsz > attrsz) 378 return (DLADM_STATUS_TOOSMALL); 379 380 bcopy(retval.lr_attrval, attrval, retval.lr_attrsz); 381 return (DLADM_STATUS_OK); 382 } 383 384 /* 385 * Get next property attribute from data link configuration repository. 386 */ 387 dladm_status_t 388 dladm_getnext_conf_linkprop(dladm_handle_t handle, dladm_conf_t conf, 389 const char *last_attr, char *attr, void *attrval, size_t attrsz, 390 size_t *attrszp) 391 { 392 dlmgmt_door_linkprop_getnext_t getnext; 393 dlmgmt_linkprop_getnext_retval_t retval; 394 dladm_status_t status; 395 396 if (conf == DLADM_INVALID_CONF || attrval == NULL || 397 attrsz == 0 || attr == NULL) { 398 return (DLADM_STATUS_BADARG); 399 } 400 401 getnext.ld_cmd = DLMGMT_CMD_LINKPROP_GETNEXT; 402 getnext.ld_conf = conf; 403 (void) strlcpy(getnext.ld_last_attr, last_attr, MAXLINKATTRLEN); 404 405 if ((status = dladm_door_call(handle, &getnext, sizeof (getnext), 406 &retval, sizeof (retval))) != DLADM_STATUS_OK) { 407 return (status); 408 } 409 410 *attrszp = retval.lr_attrsz; 411 if (retval.lr_attrsz > attrsz) { 412 return (DLADM_STATUS_TOOSMALL); 413 } 414 415 (void) strlcpy(attr, retval.lr_attr, MAXLINKATTRLEN); 416 bcopy(retval.lr_attrval, attrval, retval.lr_attrsz); 417 return (DLADM_STATUS_OK); 418 } 419 420 /* 421 * Get the link ID that is associated with the given name. 422 */ 423 dladm_status_t 424 dladm_name2info(dladm_handle_t handle, const char *link, datalink_id_t *linkidp, 425 uint32_t *flagp, datalink_class_t *classp, uint32_t *mediap) 426 { 427 dlmgmt_door_getlinkid_t getlinkid; 428 dlmgmt_getlinkid_retval_t retval; 429 datalink_id_t linkid; 430 dladm_status_t status; 431 432 getlinkid.ld_cmd = DLMGMT_CMD_GETLINKID; 433 (void) strlcpy(getlinkid.ld_link, link, MAXLINKNAMELEN); 434 435 if ((status = dladm_door_call(handle, &getlinkid, sizeof (getlinkid), 436 &retval, sizeof (retval))) != DLADM_STATUS_OK) { 437 return (status); 438 } 439 440 linkid = retval.lr_linkid; 441 if (retval.lr_class == DATALINK_CLASS_PHYS && 442 retval.lr_flags & DLMGMT_ACTIVE) { 443 /* 444 * An active physical link reported by the dlmgmtd daemon 445 * might not be active anymore. Check and set its real status. 446 */ 447 status = i_dladm_phys_status(handle, linkid, &retval.lr_flags); 448 if (status != DLADM_STATUS_OK) 449 return (status); 450 } 451 452 if (linkidp != NULL) 453 *linkidp = linkid; 454 if (flagp != NULL) { 455 *flagp = retval.lr_flags & DLMGMT_ACTIVE ? DLADM_OPT_ACTIVE : 0; 456 *flagp |= (retval.lr_flags & DLMGMT_PERSIST) ? 457 DLADM_OPT_PERSIST : 0; 458 } 459 if (classp != NULL) 460 *classp = retval.lr_class; 461 if (mediap != NULL) 462 *mediap = retval.lr_media; 463 464 return (DLADM_STATUS_OK); 465 } 466 467 /* 468 * Get the link name that is associated with the given id. 469 */ 470 dladm_status_t 471 dladm_datalink_id2info(dladm_handle_t handle, datalink_id_t linkid, 472 uint32_t *flagp, datalink_class_t *classp, uint32_t *mediap, char *link, 473 size_t len) 474 { 475 dlmgmt_door_getname_t getname; 476 dlmgmt_getname_retval_t retval; 477 dladm_status_t status; 478 479 if ((linkid == DATALINK_INVALID_LINKID) || (link != NULL && len == 0) || 480 (link == NULL && len != 0)) { 481 return (DLADM_STATUS_BADARG); 482 } 483 484 getname.ld_cmd = DLMGMT_CMD_GETNAME; 485 getname.ld_linkid = linkid; 486 if ((status = dladm_door_call(handle, &getname, sizeof (getname), 487 &retval, sizeof (retval))) != DLADM_STATUS_OK) { 488 return (status); 489 } 490 491 if (len != 0 && (strlen(retval.lr_link) + 1 > len)) 492 return (DLADM_STATUS_TOOSMALL); 493 494 if (retval.lr_class == DATALINK_CLASS_PHYS && 495 retval.lr_flags & DLMGMT_ACTIVE) { 496 /* 497 * An active physical link reported by the dlmgmtd daemon 498 * might not be active anymore. Check and set its real status. 499 */ 500 status = i_dladm_phys_status(handle, linkid, &retval.lr_flags); 501 if (status != DLADM_STATUS_OK) 502 return (status); 503 } 504 505 if (link != NULL) 506 (void) strlcpy(link, retval.lr_link, len); 507 if (classp != NULL) 508 *classp = retval.lr_class; 509 if (mediap != NULL) 510 *mediap = retval.lr_media; 511 if (flagp != NULL) { 512 *flagp = retval.lr_flags & DLMGMT_ACTIVE ? 513 DLADM_OPT_ACTIVE : 0; 514 *flagp |= (retval.lr_flags & DLMGMT_PERSIST) ? 515 DLADM_OPT_PERSIST : 0; 516 } 517 return (DLADM_STATUS_OK); 518 } 519 520 /* 521 * Set the given attr with the given attrval for the given link. 522 */ 523 dladm_status_t 524 dladm_set_conf_field(dladm_handle_t handle, dladm_conf_t conf, const char *attr, 525 dladm_datatype_t type, const void *attrval) 526 { 527 dlmgmt_door_setattr_t setattr; 528 dlmgmt_setattr_retval_t retval; 529 size_t attrsz; 530 531 if (attr == NULL || attrval == NULL) 532 return (DLADM_STATUS_BADARG); 533 534 if (type == DLADM_TYPE_STR) 535 attrsz = strlen(attrval) + 1; 536 else 537 attrsz = dladm_datatype_size[type]; 538 539 if (attrsz > MAXLINKATTRVALLEN) 540 return (DLADM_STATUS_TOOSMALL); 541 542 setattr.ld_cmd = DLMGMT_CMD_SETATTR; 543 setattr.ld_conf = conf; 544 (void) strlcpy(setattr.ld_attr, attr, MAXLINKATTRLEN); 545 setattr.ld_attrsz = attrsz; 546 setattr.ld_type = type; 547 bcopy(attrval, &setattr.ld_attrval, attrsz); 548 549 return (dladm_door_call(handle, &setattr, sizeof (setattr), &retval, 550 sizeof (retval))); 551 } 552 553 /* 554 * Unset the given attr the given link. 555 */ 556 dladm_status_t 557 dladm_unset_conf_field(dladm_handle_t handle, dladm_conf_t conf, 558 const char *attr) 559 { 560 dlmgmt_door_unsetattr_t unsetattr; 561 dlmgmt_unsetattr_retval_t retval; 562 563 if (attr == NULL) 564 return (DLADM_STATUS_BADARG); 565 566 unsetattr.ld_cmd = DLMGMT_CMD_UNSETATTR; 567 unsetattr.ld_conf = conf; 568 (void) strlcpy(unsetattr.ld_attr, attr, MAXLINKATTRLEN); 569 570 return (dladm_door_call(handle, &unsetattr, sizeof (unsetattr), &retval, 571 sizeof (retval))); 572 } 573 574 /* 575 * Remove the given link ID and its entry from the data link configuration 576 * repository. 577 */ 578 dladm_status_t 579 dladm_remove_conf(dladm_handle_t handle, datalink_id_t linkid) 580 { 581 dlmgmt_door_removeconf_t removeconf; 582 dlmgmt_removeconf_retval_t retval; 583 584 removeconf.ld_cmd = DLMGMT_CMD_REMOVECONF; 585 removeconf.ld_linkid = linkid; 586 587 return (dladm_door_call(handle, &removeconf, sizeof (removeconf), 588 &retval, sizeof (retval))); 589 } 590 591 /* 592 * Free the contents of the link structure. 593 */ 594 void 595 dladm_destroy_conf(dladm_handle_t handle, dladm_conf_t conf) 596 { 597 dlmgmt_door_destroyconf_t destroyconf; 598 dlmgmt_destroyconf_retval_t retval; 599 600 if (conf == DLADM_INVALID_CONF) 601 return; 602 603 destroyconf.ld_cmd = DLMGMT_CMD_DESTROYCONF; 604 destroyconf.ld_conf = conf; 605 606 (void) dladm_door_call(handle, &destroyconf, sizeof (destroyconf), 607 &retval, sizeof (retval)); 608 } 609