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 rsize) 56 { 57 door_arg_t darg; 58 int fd; 59 dladm_status_t status = DLADM_STATUS_OK; 60 61 if ((fd = open(DLMGMT_DOOR, O_RDONLY)) == -1) 62 return (dladm_errno2status(errno)); 63 64 darg.data_ptr = arg; 65 darg.data_size = asize; 66 darg.desc_ptr = NULL; 67 darg.desc_num = 0; 68 darg.rbuf = rbuf; 69 darg.rsize = rsize; 70 71 if (door_call(fd, &darg) == -1) 72 status = dladm_errno2status(errno); 73 (void) close(fd); 74 75 if (status != DLADM_STATUS_OK) 76 return (status); 77 78 if (darg.rbuf != rbuf) { 79 /* 80 * The size of the input rbuf is not big enough so that 81 * the door allocate the rbuf itself. In this case, simply 82 * think something wrong with the door call. 83 */ 84 (void) munmap(darg.rbuf, darg.rsize); 85 return (DLADM_STATUS_TOOSMALL); 86 } 87 if (darg.rsize != rsize) 88 return (DLADM_STATUS_FAILED); 89 90 return (dladm_errno2status(((dlmgmt_retval_t *)rbuf)->lr_err)); 91 } 92 93 /* 94 * Allocate a new linkid with the given name. Return the new linkid. 95 */ 96 dladm_status_t 97 dladm_create_datalink_id(const char *link, datalink_class_t class, 98 uint32_t media, uint32_t flags, 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(&createid, sizeof (createid), &retval, 122 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(datalink_id_t linkid, 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(&destroyid, sizeof (destroyid), 146 &retval, 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(datalink_id_t linkid, 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(&remapid, sizeof (remapid), 163 &retval, sizeof (retval))); 164 } 165 166 /* 167 * Make a given link ID active. 168 */ 169 dladm_status_t 170 dladm_up_datalink_id(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(&upid, sizeof (upid), 179 &retval, 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(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(&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(datalink_id_t linkid, uint32_t *flagsp) 216 { 217 dladm_phys_attr_t dpa; 218 dladm_status_t status; 219 220 assert((*flagsp) & DLMGMT_ACTIVE); 221 222 status = dladm_phys_info(linkid, &dpa, DLADM_OPT_ACTIVE); 223 if (status == DLADM_STATUS_NOTFOUND) { 224 /* 225 * No active status, this link was removed. Update its status 226 * in the daemon and delete all active linkprops. 227 */ 228 (void) dladm_destroy_datalink_id(linkid, DLADM_OPT_ACTIVE); 229 (void) dladm_set_linkprop(linkid, NULL, NULL, 0, 230 DLADM_OPT_ACTIVE); 231 232 (*flagsp) &= ~DLMGMT_ACTIVE; 233 status = DLADM_STATUS_OK; 234 } 235 return (status); 236 } 237 238 /* 239 * Walk each entry in the data link configuration repository and 240 * call fn on the linkid and arg. 241 */ 242 dladm_status_t 243 dladm_walk_datalink_id(int (*fn)(datalink_id_t, void *), void *argp, 244 datalink_class_t class, datalink_media_t dmedia, uint32_t flags) 245 { 246 dlmgmt_door_getnext_t getnext; 247 dlmgmt_getnext_retval_t retval; 248 uint32_t dlmgmt_flags; 249 datalink_id_t linkid = DATALINK_INVALID_LINKID; 250 dladm_status_t status = DLADM_STATUS_OK; 251 252 if (fn == NULL) 253 return (DLADM_STATUS_BADARG); 254 255 dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0; 256 dlmgmt_flags |= ((flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0); 257 258 getnext.ld_cmd = DLMGMT_CMD_GETNEXT; 259 getnext.ld_class = class; 260 getnext.ld_dmedia = dmedia; 261 getnext.ld_flags = dlmgmt_flags; 262 263 do { 264 getnext.ld_linkid = linkid; 265 if ((status = dladm_door_call(&getnext, sizeof (getnext), 266 &retval, sizeof (retval))) != DLADM_STATUS_OK) { 267 /* 268 * done with walking 269 */ 270 break; 271 } 272 273 linkid = retval.lr_linkid; 274 if ((retval.lr_class == DATALINK_CLASS_PHYS) && 275 (retval.lr_flags & DLMGMT_ACTIVE)) { 276 /* 277 * An active physical link reported by the dlmgmtd 278 * daemon might not be active anymore. Check its 279 * real status. 280 */ 281 if (i_dladm_phys_status(linkid, &retval.lr_flags) != 282 DLADM_STATUS_OK) { 283 continue; 284 } 285 286 if (!(dlmgmt_flags & retval.lr_flags)) 287 continue; 288 } 289 290 if (fn(linkid, argp) == DLADM_WALK_TERMINATE) 291 break; 292 } while (linkid != DATALINK_INVALID_LINKID); 293 294 return (status); 295 } 296 297 /* 298 * Get the link properties structure for the given link. 299 */ 300 dladm_status_t 301 dladm_read_conf(datalink_id_t linkid, dladm_conf_t *confp) 302 { 303 dlmgmt_door_readconf_t readconf; 304 dlmgmt_readconf_retval_t retval; 305 dladm_status_t status; 306 307 if (linkid == DATALINK_INVALID_LINKID || confp == NULL) 308 return (DLADM_STATUS_BADARG); 309 310 readconf.ld_linkid = linkid; 311 readconf.ld_cmd = DLMGMT_CMD_READCONF; 312 313 if ((status = dladm_door_call(&readconf, sizeof (readconf), 314 &retval, sizeof (retval))) == DLADM_STATUS_OK) { 315 *confp = retval.lr_conf; 316 } 317 return (status); 318 } 319 320 /* 321 * Commit the given link to the data link configuration repository so 322 * that it will persist across reboots. 323 */ 324 dladm_status_t 325 dladm_write_conf(dladm_conf_t conf) 326 { 327 dlmgmt_door_writeconf_t writeconf; 328 dlmgmt_writeconf_retval_t retval; 329 330 if (conf == DLADM_INVALID_CONF) 331 return (DLADM_STATUS_BADARG); 332 333 writeconf.ld_cmd = DLMGMT_CMD_WRITECONF; 334 writeconf.ld_conf = conf; 335 336 return (dladm_door_call(&writeconf, sizeof (writeconf), 337 &retval, sizeof (retval))); 338 } 339 340 /* 341 * Given a link ID and a key, get the matching information from 342 * data link configuration repository. 343 */ 344 dladm_status_t 345 dladm_get_conf_field(dladm_conf_t conf, const char *attr, void *attrval, 346 size_t attrsz) 347 { 348 dlmgmt_door_getattr_t getattr; 349 dlmgmt_getattr_retval_t retval; 350 dladm_status_t status; 351 352 if (conf == DLADM_INVALID_CONF || attrval == NULL || 353 attrsz == 0 || attr == NULL) { 354 return (DLADM_STATUS_BADARG); 355 } 356 357 getattr.ld_cmd = DLMGMT_CMD_GETATTR; 358 getattr.ld_conf = conf; 359 (void) strlcpy(getattr.ld_attr, attr, MAXLINKATTRLEN); 360 361 if ((status = dladm_door_call(&getattr, sizeof (getattr), &retval, 362 sizeof (retval))) != DLADM_STATUS_OK) { 363 return (status); 364 } 365 366 if (retval.lr_attrsz > attrsz) 367 return (DLADM_STATUS_TOOSMALL); 368 369 bcopy(retval.lr_attrval, attrval, retval.lr_attrsz); 370 return (DLADM_STATUS_OK); 371 } 372 373 /* 374 * Get the link ID that is associated with the given name. 375 */ 376 dladm_status_t 377 dladm_name2info(const char *link, datalink_id_t *linkidp, uint32_t *flagp, 378 datalink_class_t *classp, uint32_t *mediap) 379 { 380 dlmgmt_door_getlinkid_t getlinkid; 381 dlmgmt_getlinkid_retval_t retval; 382 datalink_id_t linkid; 383 dladm_status_t status; 384 385 getlinkid.ld_cmd = DLMGMT_CMD_GETLINKID; 386 (void) strlcpy(getlinkid.ld_link, link, MAXLINKNAMELEN); 387 388 if ((status = dladm_door_call(&getlinkid, sizeof (getlinkid), 389 &retval, sizeof (retval))) != DLADM_STATUS_OK) { 390 return (status); 391 } 392 393 linkid = retval.lr_linkid; 394 if (retval.lr_class == DATALINK_CLASS_PHYS && 395 retval.lr_flags & DLMGMT_ACTIVE) { 396 /* 397 * An active physical link reported by the dlmgmtd daemon 398 * might not be active anymore. Check and set its real status. 399 */ 400 status = i_dladm_phys_status(linkid, &retval.lr_flags); 401 if (status != DLADM_STATUS_OK) 402 return (status); 403 } 404 405 if (linkidp != NULL) 406 *linkidp = linkid; 407 if (flagp != NULL) { 408 *flagp = retval.lr_flags & DLMGMT_ACTIVE ? DLADM_OPT_ACTIVE : 0; 409 *flagp |= (retval.lr_flags & DLMGMT_PERSIST) ? 410 DLADM_OPT_PERSIST : 0; 411 } 412 if (classp != NULL) 413 *classp = retval.lr_class; 414 if (mediap != NULL) 415 *mediap = retval.lr_media; 416 417 return (DLADM_STATUS_OK); 418 } 419 420 /* 421 * Get the link name that is associated with the given id. 422 */ 423 dladm_status_t 424 dladm_datalink_id2info(datalink_id_t linkid, uint32_t *flagp, 425 datalink_class_t *classp, uint32_t *mediap, char *link, size_t len) 426 { 427 dlmgmt_door_getname_t getname; 428 dlmgmt_getname_retval_t retval; 429 dladm_status_t status; 430 431 if ((linkid == DATALINK_INVALID_LINKID) || (link != NULL && len == 0) || 432 (link == NULL && len != 0)) { 433 return (DLADM_STATUS_BADARG); 434 } 435 436 getname.ld_cmd = DLMGMT_CMD_GETNAME; 437 getname.ld_linkid = linkid; 438 if ((status = dladm_door_call(&getname, sizeof (getname), &retval, 439 sizeof (retval))) != DLADM_STATUS_OK) { 440 return (status); 441 } 442 443 if (len != 0 && (strlen(retval.lr_link) + 1 > len)) 444 return (DLADM_STATUS_TOOSMALL); 445 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(linkid, &retval.lr_flags); 453 if (status != DLADM_STATUS_OK) 454 return (status); 455 } 456 457 if (link != NULL) 458 (void) strlcpy(link, retval.lr_link, len); 459 if (classp != NULL) 460 *classp = retval.lr_class; 461 if (mediap != NULL) 462 *mediap = retval.lr_media; 463 if (flagp != NULL) { 464 *flagp = retval.lr_flags & DLMGMT_ACTIVE ? 465 DLADM_OPT_ACTIVE : 0; 466 *flagp |= (retval.lr_flags & DLMGMT_PERSIST) ? 467 DLADM_OPT_PERSIST : 0; 468 } 469 return (DLADM_STATUS_OK); 470 } 471 472 /* 473 * Set the given attr with the given attrval for the given link. 474 */ 475 dladm_status_t 476 dladm_set_conf_field(dladm_conf_t conf, const char *attr, 477 dladm_datatype_t type, const void *attrval) 478 { 479 dlmgmt_door_setattr_t setattr; 480 dlmgmt_setattr_retval_t retval; 481 size_t attrsz; 482 483 if (attr == NULL || attrval == NULL) 484 return (DLADM_STATUS_BADARG); 485 486 if (type == DLADM_TYPE_STR) 487 attrsz = strlen(attrval) + 1; 488 else 489 attrsz = dladm_datatype_size[type]; 490 491 if (attrsz > MAXLINKATTRVALLEN) 492 return (DLADM_STATUS_TOOSMALL); 493 494 setattr.ld_cmd = DLMGMT_CMD_SETATTR; 495 setattr.ld_conf = conf; 496 (void) strlcpy(setattr.ld_attr, attr, MAXLINKATTRLEN); 497 setattr.ld_attrsz = attrsz; 498 setattr.ld_type = type; 499 bcopy(attrval, &setattr.ld_attrval, attrsz); 500 501 return (dladm_door_call(&setattr, sizeof (setattr), 502 &retval, sizeof (retval))); 503 } 504 505 /* 506 * Unset the given attr the given link. 507 */ 508 dladm_status_t 509 dladm_unset_conf_field(dladm_conf_t conf, const char *attr) 510 { 511 dlmgmt_door_unsetattr_t unsetattr; 512 dlmgmt_unsetattr_retval_t retval; 513 514 if (attr == NULL) 515 return (DLADM_STATUS_BADARG); 516 517 unsetattr.ld_cmd = DLMGMT_CMD_UNSETATTR; 518 unsetattr.ld_conf = conf; 519 (void) strlcpy(unsetattr.ld_attr, attr, MAXLINKATTRLEN); 520 521 return (dladm_door_call(&unsetattr, sizeof (unsetattr), 522 &retval, sizeof (retval))); 523 } 524 525 /* 526 * Remove the given link ID and its entry from the data link configuration 527 * repository. 528 */ 529 dladm_status_t 530 dladm_remove_conf(datalink_id_t linkid) 531 { 532 dlmgmt_door_removeconf_t removeconf; 533 dlmgmt_removeconf_retval_t retval; 534 535 removeconf.ld_cmd = DLMGMT_CMD_REMOVECONF; 536 removeconf.ld_linkid = linkid; 537 538 return (dladm_door_call(&removeconf, sizeof (removeconf), 539 &retval, sizeof (retval))); 540 } 541 542 /* 543 * Free the contents of the link structure. 544 */ 545 void 546 dladm_destroy_conf(dladm_conf_t conf) 547 { 548 dlmgmt_door_destroyconf_t destroyconf; 549 dlmgmt_destroyconf_retval_t retval; 550 551 if (conf == DLADM_INVALID_CONF) 552 return; 553 554 destroyconf.ld_cmd = DLMGMT_CMD_DESTROYCONF; 555 destroyconf.ld_conf = conf; 556 557 (void) dladm_door_call(&destroyconf, sizeof (destroyconf), 558 &retval, sizeof (retval)); 559 } 560