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(void *arg, size_t asize, void *rbuf, size_t rsize) 54 { 55 door_arg_t darg; 56 int fd; 57 dladm_status_t status = DLADM_STATUS_OK; 58 59 if ((fd = open(DLMGMT_DOOR, O_RDONLY)) == -1) 60 return (dladm_errno2status(errno)); 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 if (door_call(fd, &darg) == -1) 70 status = dladm_errno2status(errno); 71 (void) close(fd); 72 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(const char *link, datalink_class_t class, 96 uint32_t media, uint32_t flags, 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(&createid, sizeof (createid), &retval, 120 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(datalink_id_t linkid, uint32_t flags) 131 { 132 dlmgmt_door_destroyid_t destroyid; 133 dlmgmt_destroyid_retval_t retval; 134 uint32_t dlmgmt_flags; 135 136 dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0; 137 dlmgmt_flags |= ((flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0); 138 139 destroyid.ld_cmd = DLMGMT_CMD_DESTROY_LINKID; 140 destroyid.ld_linkid = linkid; 141 destroyid.ld_flags = dlmgmt_flags; 142 143 return (dladm_door_call(&destroyid, sizeof (destroyid), 144 &retval, sizeof (retval))); 145 } 146 147 /* 148 * Remap a given link ID to a new name. 149 */ 150 dladm_status_t 151 dladm_remap_datalink_id(datalink_id_t linkid, const char *link) 152 { 153 dlmgmt_door_remapid_t remapid; 154 dlmgmt_remapid_retval_t retval; 155 156 remapid.ld_cmd = DLMGMT_CMD_REMAP_LINKID; 157 remapid.ld_linkid = linkid; 158 (void) strlcpy(remapid.ld_link, link, MAXLINKNAMELEN); 159 160 return (dladm_door_call(&remapid, sizeof (remapid), 161 &retval, sizeof (retval))); 162 } 163 164 /* 165 * Make a given link ID active. 166 */ 167 dladm_status_t 168 dladm_up_datalink_id(datalink_id_t linkid) 169 { 170 dlmgmt_door_upid_t upid; 171 dlmgmt_upid_retval_t retval; 172 173 upid.ld_cmd = DLMGMT_CMD_UP_LINKID; 174 upid.ld_linkid = linkid; 175 176 return (dladm_door_call(&upid, sizeof (upid), 177 &retval, sizeof (retval))); 178 } 179 180 /* 181 * Create a new link with the given name. Return the new link's handle 182 */ 183 dladm_status_t 184 dladm_create_conf(const char *link, datalink_id_t linkid, 185 datalink_class_t class, uint32_t media, dladm_conf_t *confp) 186 { 187 dlmgmt_door_createconf_t createconf; 188 dlmgmt_createconf_retval_t retval; 189 dladm_status_t status; 190 191 if (link == NULL || confp == NULL) 192 return (DLADM_STATUS_BADARG); 193 194 (void) strlcpy(createconf.ld_link, link, MAXLINKNAMELEN); 195 createconf.ld_class = class; 196 createconf.ld_media = media; 197 createconf.ld_linkid = linkid; 198 createconf.ld_cmd = DLMGMT_CMD_CREATECONF; 199 200 if ((status = dladm_door_call(&createconf, sizeof (createconf), 201 &retval, sizeof (retval))) == DLADM_STATUS_OK) { 202 *confp = retval.lr_conf; 203 } 204 return (status); 205 } 206 207 /* 208 * An active physical link reported by the dlmgmtd daemon might not be active 209 * anymore as this link might be removed during system shutdown. Check its 210 * real status by calling dladm_phys_info(). 211 */ 212 dladm_status_t 213 i_dladm_phys_status(datalink_id_t linkid, uint32_t *flagsp) 214 { 215 dladm_phys_attr_t dpa; 216 dladm_status_t status; 217 218 assert((*flagsp) & DLMGMT_ACTIVE); 219 220 status = dladm_phys_info(linkid, &dpa, DLADM_OPT_ACTIVE); 221 if (status == DLADM_STATUS_NOTFOUND) { 222 /* 223 * No active status, this link was removed. Update its status 224 * in the daemon and delete all active linkprops. 225 * 226 * Note that the operation could fail. If it does, return 227 * failure now since otherwise dladm_set_linkprop() might 228 * call back to i_dladm_phys_status() recursively. 229 */ 230 status = dladm_destroy_datalink_id(linkid, DLADM_OPT_ACTIVE); 231 if (status != DLADM_STATUS_OK) 232 return (status); 233 234 (void) dladm_set_linkprop(linkid, NULL, NULL, 0, 235 DLADM_OPT_ACTIVE); 236 237 (*flagsp) &= ~DLMGMT_ACTIVE; 238 status = DLADM_STATUS_OK; 239 } 240 return (status); 241 } 242 243 /* 244 * Walk each entry in the data link configuration repository and 245 * call fn on the linkid and arg. 246 */ 247 dladm_status_t 248 dladm_walk_datalink_id(int (*fn)(datalink_id_t, void *), void *argp, 249 datalink_class_t class, datalink_media_t dmedia, uint32_t flags) 250 { 251 dlmgmt_door_getnext_t getnext; 252 dlmgmt_getnext_retval_t retval; 253 uint32_t dlmgmt_flags; 254 datalink_id_t linkid = DATALINK_INVALID_LINKID; 255 dladm_status_t status = DLADM_STATUS_OK; 256 257 if (fn == NULL) 258 return (DLADM_STATUS_BADARG); 259 260 dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0; 261 dlmgmt_flags |= ((flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0); 262 263 getnext.ld_cmd = DLMGMT_CMD_GETNEXT; 264 getnext.ld_class = class; 265 getnext.ld_dmedia = dmedia; 266 getnext.ld_flags = dlmgmt_flags; 267 268 do { 269 getnext.ld_linkid = linkid; 270 if ((status = dladm_door_call(&getnext, sizeof (getnext), 271 &retval, sizeof (retval))) != DLADM_STATUS_OK) { 272 /* 273 * done with walking 274 */ 275 break; 276 } 277 278 linkid = retval.lr_linkid; 279 if ((retval.lr_class == DATALINK_CLASS_PHYS) && 280 (retval.lr_flags & DLMGMT_ACTIVE)) { 281 /* 282 * An active physical link reported by the dlmgmtd 283 * daemon might not be active anymore. Check its 284 * real status. 285 */ 286 if (i_dladm_phys_status(linkid, &retval.lr_flags) != 287 DLADM_STATUS_OK) { 288 continue; 289 } 290 291 if (!(dlmgmt_flags & retval.lr_flags)) 292 continue; 293 } 294 295 if (fn(linkid, argp) == DLADM_WALK_TERMINATE) 296 break; 297 } while (linkid != DATALINK_INVALID_LINKID); 298 299 return (status); 300 } 301 302 /* 303 * Get the link properties structure for the given link. 304 */ 305 dladm_status_t 306 dladm_read_conf(datalink_id_t linkid, dladm_conf_t *confp) 307 { 308 dlmgmt_door_readconf_t readconf; 309 dlmgmt_readconf_retval_t retval; 310 dladm_status_t status; 311 312 if (linkid == DATALINK_INVALID_LINKID || confp == NULL) 313 return (DLADM_STATUS_BADARG); 314 315 readconf.ld_linkid = linkid; 316 readconf.ld_cmd = DLMGMT_CMD_READCONF; 317 318 if ((status = dladm_door_call(&readconf, sizeof (readconf), 319 &retval, sizeof (retval))) == DLADM_STATUS_OK) { 320 *confp = retval.lr_conf; 321 } 322 return (status); 323 } 324 325 /* 326 * Commit the given link to the data link configuration repository so 327 * that it will persist across reboots. 328 */ 329 dladm_status_t 330 dladm_write_conf(dladm_conf_t conf) 331 { 332 dlmgmt_door_writeconf_t writeconf; 333 dlmgmt_writeconf_retval_t retval; 334 335 if (conf == DLADM_INVALID_CONF) 336 return (DLADM_STATUS_BADARG); 337 338 writeconf.ld_cmd = DLMGMT_CMD_WRITECONF; 339 writeconf.ld_conf = conf; 340 341 return (dladm_door_call(&writeconf, sizeof (writeconf), 342 &retval, sizeof (retval))); 343 } 344 345 /* 346 * Given a link ID and a key, get the matching information from 347 * data link configuration repository. 348 */ 349 dladm_status_t 350 dladm_get_conf_field(dladm_conf_t conf, const char *attr, void *attrval, 351 size_t attrsz) 352 { 353 dlmgmt_door_getattr_t getattr; 354 dlmgmt_getattr_retval_t retval; 355 dladm_status_t status; 356 357 if (conf == DLADM_INVALID_CONF || attrval == NULL || 358 attrsz == 0 || attr == NULL) { 359 return (DLADM_STATUS_BADARG); 360 } 361 362 getattr.ld_cmd = DLMGMT_CMD_GETATTR; 363 getattr.ld_conf = conf; 364 (void) strlcpy(getattr.ld_attr, attr, MAXLINKATTRLEN); 365 366 if ((status = dladm_door_call(&getattr, sizeof (getattr), &retval, 367 sizeof (retval))) != DLADM_STATUS_OK) { 368 return (status); 369 } 370 371 if (retval.lr_attrsz > attrsz) 372 return (DLADM_STATUS_TOOSMALL); 373 374 bcopy(retval.lr_attrval, attrval, retval.lr_attrsz); 375 return (DLADM_STATUS_OK); 376 } 377 378 /* 379 * Get the link ID that is associated with the given name. 380 */ 381 dladm_status_t 382 dladm_name2info(const char *link, datalink_id_t *linkidp, uint32_t *flagp, 383 datalink_class_t *classp, uint32_t *mediap) 384 { 385 dlmgmt_door_getlinkid_t getlinkid; 386 dlmgmt_getlinkid_retval_t retval; 387 datalink_id_t linkid; 388 dladm_status_t status; 389 390 getlinkid.ld_cmd = DLMGMT_CMD_GETLINKID; 391 (void) strlcpy(getlinkid.ld_link, link, MAXLINKNAMELEN); 392 393 if ((status = dladm_door_call(&getlinkid, sizeof (getlinkid), 394 &retval, sizeof (retval))) != DLADM_STATUS_OK) { 395 return (status); 396 } 397 398 linkid = retval.lr_linkid; 399 if (retval.lr_class == DATALINK_CLASS_PHYS && 400 retval.lr_flags & DLMGMT_ACTIVE) { 401 /* 402 * An active physical link reported by the dlmgmtd daemon 403 * might not be active anymore. Check and set its real status. 404 */ 405 status = i_dladm_phys_status(linkid, &retval.lr_flags); 406 if (status != DLADM_STATUS_OK) 407 return (status); 408 } 409 410 if (linkidp != NULL) 411 *linkidp = linkid; 412 if (flagp != NULL) { 413 *flagp = retval.lr_flags & DLMGMT_ACTIVE ? DLADM_OPT_ACTIVE : 0; 414 *flagp |= (retval.lr_flags & DLMGMT_PERSIST) ? 415 DLADM_OPT_PERSIST : 0; 416 } 417 if (classp != NULL) 418 *classp = retval.lr_class; 419 if (mediap != NULL) 420 *mediap = retval.lr_media; 421 422 return (DLADM_STATUS_OK); 423 } 424 425 /* 426 * Get the link name that is associated with the given id. 427 */ 428 dladm_status_t 429 dladm_datalink_id2info(datalink_id_t linkid, uint32_t *flagp, 430 datalink_class_t *classp, uint32_t *mediap, char *link, size_t len) 431 { 432 dlmgmt_door_getname_t getname; 433 dlmgmt_getname_retval_t retval; 434 dladm_status_t status; 435 436 if ((linkid == DATALINK_INVALID_LINKID) || (link != NULL && len == 0) || 437 (link == NULL && len != 0)) { 438 return (DLADM_STATUS_BADARG); 439 } 440 441 getname.ld_cmd = DLMGMT_CMD_GETNAME; 442 getname.ld_linkid = linkid; 443 if ((status = dladm_door_call(&getname, sizeof (getname), &retval, 444 sizeof (retval))) != DLADM_STATUS_OK) { 445 return (status); 446 } 447 448 if (len != 0 && (strlen(retval.lr_link) + 1 > len)) 449 return (DLADM_STATUS_TOOSMALL); 450 451 if (retval.lr_class == DATALINK_CLASS_PHYS && 452 retval.lr_flags & DLMGMT_ACTIVE) { 453 /* 454 * An active physical link reported by the dlmgmtd daemon 455 * might not be active anymore. Check and set its real status. 456 */ 457 status = i_dladm_phys_status(linkid, &retval.lr_flags); 458 if (status != DLADM_STATUS_OK) 459 return (status); 460 } 461 462 if (link != NULL) 463 (void) strlcpy(link, retval.lr_link, len); 464 if (classp != NULL) 465 *classp = retval.lr_class; 466 if (mediap != NULL) 467 *mediap = retval.lr_media; 468 if (flagp != NULL) { 469 *flagp = retval.lr_flags & DLMGMT_ACTIVE ? 470 DLADM_OPT_ACTIVE : 0; 471 *flagp |= (retval.lr_flags & DLMGMT_PERSIST) ? 472 DLADM_OPT_PERSIST : 0; 473 } 474 return (DLADM_STATUS_OK); 475 } 476 477 /* 478 * Set the given attr with the given attrval for the given link. 479 */ 480 dladm_status_t 481 dladm_set_conf_field(dladm_conf_t conf, const char *attr, 482 dladm_datatype_t type, const void *attrval) 483 { 484 dlmgmt_door_setattr_t setattr; 485 dlmgmt_setattr_retval_t retval; 486 size_t attrsz; 487 488 if (attr == NULL || attrval == NULL) 489 return (DLADM_STATUS_BADARG); 490 491 if (type == DLADM_TYPE_STR) 492 attrsz = strlen(attrval) + 1; 493 else 494 attrsz = dladm_datatype_size[type]; 495 496 if (attrsz > MAXLINKATTRVALLEN) 497 return (DLADM_STATUS_TOOSMALL); 498 499 setattr.ld_cmd = DLMGMT_CMD_SETATTR; 500 setattr.ld_conf = conf; 501 (void) strlcpy(setattr.ld_attr, attr, MAXLINKATTRLEN); 502 setattr.ld_attrsz = attrsz; 503 setattr.ld_type = type; 504 bcopy(attrval, &setattr.ld_attrval, attrsz); 505 506 return (dladm_door_call(&setattr, sizeof (setattr), 507 &retval, sizeof (retval))); 508 } 509 510 /* 511 * Unset the given attr the given link. 512 */ 513 dladm_status_t 514 dladm_unset_conf_field(dladm_conf_t conf, const char *attr) 515 { 516 dlmgmt_door_unsetattr_t unsetattr; 517 dlmgmt_unsetattr_retval_t retval; 518 519 if (attr == NULL) 520 return (DLADM_STATUS_BADARG); 521 522 unsetattr.ld_cmd = DLMGMT_CMD_UNSETATTR; 523 unsetattr.ld_conf = conf; 524 (void) strlcpy(unsetattr.ld_attr, attr, MAXLINKATTRLEN); 525 526 return (dladm_door_call(&unsetattr, sizeof (unsetattr), 527 &retval, sizeof (retval))); 528 } 529 530 /* 531 * Remove the given link ID and its entry from the data link configuration 532 * repository. 533 */ 534 dladm_status_t 535 dladm_remove_conf(datalink_id_t linkid) 536 { 537 dlmgmt_door_removeconf_t removeconf; 538 dlmgmt_removeconf_retval_t retval; 539 540 removeconf.ld_cmd = DLMGMT_CMD_REMOVECONF; 541 removeconf.ld_linkid = linkid; 542 543 return (dladm_door_call(&removeconf, sizeof (removeconf), 544 &retval, sizeof (retval))); 545 } 546 547 /* 548 * Free the contents of the link structure. 549 */ 550 void 551 dladm_destroy_conf(dladm_conf_t conf) 552 { 553 dlmgmt_door_destroyconf_t destroyconf; 554 dlmgmt_destroyconf_retval_t retval; 555 556 if (conf == DLADM_INVALID_CONF) 557 return; 558 559 destroyconf.ld_cmd = DLMGMT_CMD_DESTROYCONF; 560 destroyconf.ld_conf = conf; 561 562 (void) dladm_door_call(&destroyconf, sizeof (destroyconf), 563 &retval, sizeof (retval)); 564 } 565