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 the link ID that is associated with the given name. 386 */ 387 dladm_status_t 388 dladm_name2info(dladm_handle_t handle, const char *link, datalink_id_t *linkidp, 389 uint32_t *flagp, datalink_class_t *classp, uint32_t *mediap) 390 { 391 dlmgmt_door_getlinkid_t getlinkid; 392 dlmgmt_getlinkid_retval_t retval; 393 datalink_id_t linkid; 394 dladm_status_t status; 395 396 getlinkid.ld_cmd = DLMGMT_CMD_GETLINKID; 397 (void) strlcpy(getlinkid.ld_link, link, MAXLINKNAMELEN); 398 399 if ((status = dladm_door_call(handle, &getlinkid, sizeof (getlinkid), 400 &retval, sizeof (retval))) != DLADM_STATUS_OK) { 401 return (status); 402 } 403 404 linkid = retval.lr_linkid; 405 if (retval.lr_class == DATALINK_CLASS_PHYS && 406 retval.lr_flags & DLMGMT_ACTIVE) { 407 /* 408 * An active physical link reported by the dlmgmtd daemon 409 * might not be active anymore. Check and set its real status. 410 */ 411 status = i_dladm_phys_status(handle, linkid, &retval.lr_flags); 412 if (status != DLADM_STATUS_OK) 413 return (status); 414 } 415 416 if (linkidp != NULL) 417 *linkidp = linkid; 418 if (flagp != NULL) { 419 *flagp = retval.lr_flags & DLMGMT_ACTIVE ? DLADM_OPT_ACTIVE : 0; 420 *flagp |= (retval.lr_flags & DLMGMT_PERSIST) ? 421 DLADM_OPT_PERSIST : 0; 422 } 423 if (classp != NULL) 424 *classp = retval.lr_class; 425 if (mediap != NULL) 426 *mediap = retval.lr_media; 427 428 return (DLADM_STATUS_OK); 429 } 430 431 /* 432 * Get the link name that is associated with the given id. 433 */ 434 dladm_status_t 435 dladm_datalink_id2info(dladm_handle_t handle, datalink_id_t linkid, 436 uint32_t *flagp, datalink_class_t *classp, uint32_t *mediap, char *link, 437 size_t len) 438 { 439 dlmgmt_door_getname_t getname; 440 dlmgmt_getname_retval_t retval; 441 dladm_status_t status; 442 443 if ((linkid == DATALINK_INVALID_LINKID) || (link != NULL && len == 0) || 444 (link == NULL && len != 0)) { 445 return (DLADM_STATUS_BADARG); 446 } 447 448 getname.ld_cmd = DLMGMT_CMD_GETNAME; 449 getname.ld_linkid = linkid; 450 if ((status = dladm_door_call(handle, &getname, sizeof (getname), 451 &retval, sizeof (retval))) != DLADM_STATUS_OK) { 452 return (status); 453 } 454 455 if (len != 0 && (strlen(retval.lr_link) + 1 > len)) 456 return (DLADM_STATUS_TOOSMALL); 457 458 if (retval.lr_class == DATALINK_CLASS_PHYS && 459 retval.lr_flags & DLMGMT_ACTIVE) { 460 /* 461 * An active physical link reported by the dlmgmtd daemon 462 * might not be active anymore. Check and set its real status. 463 */ 464 status = i_dladm_phys_status(handle, linkid, &retval.lr_flags); 465 if (status != DLADM_STATUS_OK) 466 return (status); 467 } 468 469 if (link != NULL) 470 (void) strlcpy(link, retval.lr_link, len); 471 if (classp != NULL) 472 *classp = retval.lr_class; 473 if (mediap != NULL) 474 *mediap = retval.lr_media; 475 if (flagp != NULL) { 476 *flagp = retval.lr_flags & DLMGMT_ACTIVE ? 477 DLADM_OPT_ACTIVE : 0; 478 *flagp |= (retval.lr_flags & DLMGMT_PERSIST) ? 479 DLADM_OPT_PERSIST : 0; 480 } 481 return (DLADM_STATUS_OK); 482 } 483 484 /* 485 * Set the given attr with the given attrval for the given link. 486 */ 487 dladm_status_t 488 dladm_set_conf_field(dladm_handle_t handle, dladm_conf_t conf, const char *attr, 489 dladm_datatype_t type, const void *attrval) 490 { 491 dlmgmt_door_setattr_t setattr; 492 dlmgmt_setattr_retval_t retval; 493 size_t attrsz; 494 495 if (attr == NULL || attrval == NULL) 496 return (DLADM_STATUS_BADARG); 497 498 if (type == DLADM_TYPE_STR) 499 attrsz = strlen(attrval) + 1; 500 else 501 attrsz = dladm_datatype_size[type]; 502 503 if (attrsz > MAXLINKATTRVALLEN) 504 return (DLADM_STATUS_TOOSMALL); 505 506 setattr.ld_cmd = DLMGMT_CMD_SETATTR; 507 setattr.ld_conf = conf; 508 (void) strlcpy(setattr.ld_attr, attr, MAXLINKATTRLEN); 509 setattr.ld_attrsz = attrsz; 510 setattr.ld_type = type; 511 bcopy(attrval, &setattr.ld_attrval, attrsz); 512 513 return (dladm_door_call(handle, &setattr, sizeof (setattr), &retval, 514 sizeof (retval))); 515 } 516 517 /* 518 * Unset the given attr the given link. 519 */ 520 dladm_status_t 521 dladm_unset_conf_field(dladm_handle_t handle, dladm_conf_t conf, 522 const char *attr) 523 { 524 dlmgmt_door_unsetattr_t unsetattr; 525 dlmgmt_unsetattr_retval_t retval; 526 527 if (attr == NULL) 528 return (DLADM_STATUS_BADARG); 529 530 unsetattr.ld_cmd = DLMGMT_CMD_UNSETATTR; 531 unsetattr.ld_conf = conf; 532 (void) strlcpy(unsetattr.ld_attr, attr, MAXLINKATTRLEN); 533 534 return (dladm_door_call(handle, &unsetattr, sizeof (unsetattr), &retval, 535 sizeof (retval))); 536 } 537 538 /* 539 * Remove the given link ID and its entry from the data link configuration 540 * repository. 541 */ 542 dladm_status_t 543 dladm_remove_conf(dladm_handle_t handle, datalink_id_t linkid) 544 { 545 dlmgmt_door_removeconf_t removeconf; 546 dlmgmt_removeconf_retval_t retval; 547 548 removeconf.ld_cmd = DLMGMT_CMD_REMOVECONF; 549 removeconf.ld_linkid = linkid; 550 551 return (dladm_door_call(handle, &removeconf, sizeof (removeconf), 552 &retval, sizeof (retval))); 553 } 554 555 /* 556 * Free the contents of the link structure. 557 */ 558 void 559 dladm_destroy_conf(dladm_handle_t handle, dladm_conf_t conf) 560 { 561 dlmgmt_door_destroyconf_t destroyconf; 562 dlmgmt_destroyconf_retval_t retval; 563 564 if (conf == DLADM_INVALID_CONF) 565 return; 566 567 destroyconf.ld_cmd = DLMGMT_CMD_DESTROYCONF; 568 destroyconf.ld_conf = conf; 569 570 (void) dladm_door_call(handle, &destroyconf, sizeof (destroyconf), 571 &retval, sizeof (retval)); 572 } 573