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