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