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