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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include <sys/types.h> 26 #include <unistd.h> 27 #include <errno.h> 28 #include <fcntl.h> 29 #include <assert.h> 30 #include <ctype.h> 31 #include <strings.h> 32 #include <sys/stat.h> 33 #include <sys/dld.h> 34 #include <sys/vlan.h> 35 #include <zone.h> 36 #include <librcm.h> 37 #include <libdlpi.h> 38 #include <libdevinfo.h> 39 #include <libdlaggr.h> 40 #include <libdlvlan.h> 41 #include <libdlvnic.h> 42 #include <libdlib.h> 43 #include <libdllink.h> 44 #include <libdlmgmt.h> 45 #include <libdladm_impl.h> 46 #include <libinetutil.h> 47 48 /* 49 * Return the attributes of the specified datalink from the DLD driver. 50 */ 51 static dladm_status_t 52 i_dladm_info(dladm_handle_t handle, const datalink_id_t linkid, 53 dladm_attr_t *dap) 54 { 55 dld_ioc_attr_t dia; 56 57 dia.dia_linkid = linkid; 58 59 if (ioctl(dladm_dld_fd(handle), DLDIOC_ATTR, &dia) < 0) 60 return (dladm_errno2status(errno)); 61 62 dap->da_max_sdu = dia.dia_max_sdu; 63 64 return (DLADM_STATUS_OK); 65 } 66 67 static dladm_status_t 68 dladm_usagelog(dladm_handle_t handle, dladm_logtype_t type, 69 dld_ioc_usagelog_t *log_info) 70 { 71 if (type == DLADM_LOGTYPE_FLOW) 72 log_info->ul_type = MAC_LOGTYPE_FLOW; 73 else 74 log_info->ul_type = MAC_LOGTYPE_LINK; 75 76 if (ioctl(dladm_dld_fd(handle), DLDIOC_USAGELOG, log_info) < 0) 77 return (DLADM_STATUS_IOERR); 78 79 return (DLADM_STATUS_OK); 80 } 81 82 dladm_status_t 83 dladm_start_usagelog(dladm_handle_t handle, dladm_logtype_t type, 84 uint_t interval) 85 { 86 dld_ioc_usagelog_t log_info; 87 88 log_info.ul_onoff = B_TRUE; 89 log_info.ul_interval = interval; 90 91 return (dladm_usagelog(handle, type, &log_info)); 92 } 93 94 dladm_status_t 95 dladm_stop_usagelog(dladm_handle_t handle, dladm_logtype_t type) 96 { 97 dld_ioc_usagelog_t log_info; 98 99 log_info.ul_onoff = B_FALSE; 100 log_info.ul_interval = 0; 101 102 return (dladm_usagelog(handle, type, &log_info)); 103 } 104 105 struct i_dladm_walk_arg { 106 dladm_walkcb_t *fn; 107 void *arg; 108 }; 109 110 static int 111 i_dladm_walk(dladm_handle_t handle, datalink_id_t linkid, void *arg) 112 { 113 struct i_dladm_walk_arg *walk_arg = arg; 114 char link[MAXLINKNAMELEN]; 115 116 if (dladm_datalink_id2info(handle, linkid, NULL, NULL, NULL, link, 117 sizeof (link)) == DLADM_STATUS_OK) { 118 return (walk_arg->fn(link, walk_arg->arg)); 119 } 120 121 return (DLADM_WALK_CONTINUE); 122 } 123 124 /* 125 * Walk all datalinks. 126 */ 127 dladm_status_t 128 dladm_walk(dladm_walkcb_t *fn, dladm_handle_t handle, void *arg, 129 datalink_class_t class, datalink_media_t dmedia, uint32_t flags) 130 { 131 struct i_dladm_walk_arg walk_arg; 132 133 walk_arg.fn = fn; 134 walk_arg.arg = arg; 135 return (dladm_walk_datalink_id(i_dladm_walk, handle, &walk_arg, 136 class, dmedia, flags)); 137 } 138 139 #define MAXGRPPERLINK 64 140 141 int 142 dladm_walk_hwgrp(dladm_handle_t handle, datalink_id_t linkid, void *arg, 143 boolean_t (*fn)(void *, dladm_hwgrp_attr_t *)) 144 { 145 int bufsize, ret; 146 int nhwgrp = MAXGRPPERLINK; 147 dld_ioc_hwgrpget_t *iomp = NULL; 148 149 bufsize = sizeof (dld_ioc_hwgrpget_t) + 150 nhwgrp * sizeof (dld_hwgrpinfo_t); 151 152 if ((iomp = (dld_ioc_hwgrpget_t *)calloc(1, bufsize)) == NULL) 153 return (-1); 154 155 iomp->dih_size = nhwgrp * sizeof (dld_hwgrpinfo_t); 156 iomp->dih_linkid = linkid; 157 158 ret = ioctl(dladm_dld_fd(handle), DLDIOC_GETHWGRP, iomp); 159 if (ret == 0) { 160 int i; 161 int j; 162 dld_hwgrpinfo_t *dhip; 163 dladm_hwgrp_attr_t attr; 164 165 dhip = (dld_hwgrpinfo_t *)(iomp + 1); 166 for (i = 0; i < iomp->dih_n_groups; i++) { 167 bzero(&attr, sizeof (attr)); 168 169 (void) strlcpy(attr.hg_link_name, 170 dhip->dhi_link_name, sizeof (attr.hg_link_name)); 171 attr.hg_grp_num = dhip->dhi_grp_num; 172 attr.hg_grp_type = dhip->dhi_grp_type; 173 attr.hg_n_rings = dhip->dhi_n_rings; 174 for (j = 0; j < dhip->dhi_n_rings; j++) 175 attr.hg_rings[j] = dhip->dhi_rings[j]; 176 dladm_sort_index_list(attr.hg_rings, attr.hg_n_rings); 177 attr.hg_n_clnts = dhip->dhi_n_clnts; 178 (void) strlcpy(attr.hg_client_names, 179 dhip->dhi_clnts, sizeof (attr.hg_client_names)); 180 181 if (!(*fn)(arg, &attr)) 182 break; 183 dhip++; 184 } 185 } 186 free(iomp); 187 return (ret); 188 } 189 190 /* 191 * Invoke the specified callback for each MAC address entry defined on 192 * the specified device. 193 */ 194 int 195 dladm_walk_macaddr(dladm_handle_t handle, datalink_id_t linkid, void *arg, 196 boolean_t (*fn)(void *, dladm_macaddr_attr_t *)) 197 { 198 int bufsize, ret; 199 int nmacaddr = 1024; 200 dld_ioc_macaddrget_t *iomp = NULL; 201 202 bufsize = sizeof (dld_ioc_macaddrget_t) + 203 nmacaddr * sizeof (dld_macaddrinfo_t); 204 205 if ((iomp = (dld_ioc_macaddrget_t *)calloc(1, bufsize)) == NULL) 206 return (-1); 207 208 iomp->dig_size = nmacaddr * sizeof (dld_macaddrinfo_t); 209 iomp->dig_linkid = linkid; 210 211 ret = ioctl(dladm_dld_fd(handle), DLDIOC_MACADDRGET, iomp); 212 if (ret == 0) { 213 int i; 214 dld_macaddrinfo_t *dmip; 215 dladm_macaddr_attr_t attr; 216 217 dmip = (dld_macaddrinfo_t *)(iomp + 1); 218 for (i = 0; i < iomp->dig_count; i++) { 219 bzero(&attr, sizeof (attr)); 220 221 attr.ma_slot = dmip->dmi_slot; 222 attr.ma_flags = 0; 223 if (dmip->dmi_flags & DLDIOCMACADDR_USED) 224 attr.ma_flags |= DLADM_MACADDR_USED; 225 bcopy(dmip->dmi_addr, attr.ma_addr, 226 dmip->dmi_addrlen); 227 attr.ma_addrlen = dmip->dmi_addrlen; 228 (void) strlcpy(attr.ma_client_name, 229 dmip->dmi_client_name, MAXNAMELEN); 230 attr.ma_client_linkid = dmip->dma_client_linkid; 231 232 if (!(*fn)(arg, &attr)) 233 break; 234 dmip++; 235 } 236 } 237 free(iomp); 238 return (ret); 239 } 240 241 /* 242 * These routines are used by administration tools such as dladm(1M) to 243 * iterate through the list of MAC interfaces 244 */ 245 246 typedef struct dladm_mac_dev { 247 char dm_name[MAXNAMELEN]; 248 struct dladm_mac_dev *dm_next; 249 } dladm_mac_dev_t; 250 251 typedef struct macadm_walk { 252 dladm_mac_dev_t *dmd_dev_list; 253 } dladm_mac_walk_t; 254 255 /* 256 * Local callback invoked for each DDI_NT_NET node. 257 */ 258 /* ARGSUSED */ 259 static int 260 i_dladm_mac_walk(di_node_t node, di_minor_t minor, void *arg) 261 { 262 dladm_mac_walk_t *dmwp = arg; 263 dladm_mac_dev_t *dmdp = dmwp->dmd_dev_list; 264 dladm_mac_dev_t **last_dmdp = &dmwp->dmd_dev_list; 265 char mac[MAXNAMELEN]; 266 267 (void) snprintf(mac, MAXNAMELEN, "%s%d", 268 di_driver_name(node), di_instance(node)); 269 270 /* 271 * Skip aggregations. 272 */ 273 if (strcmp("aggr", di_driver_name(node)) == 0) 274 return (DI_WALK_CONTINUE); 275 276 /* 277 * Skip softmacs. 278 */ 279 if (strcmp("softmac", di_driver_name(node)) == 0) 280 return (DI_WALK_CONTINUE); 281 282 while (dmdp) { 283 /* 284 * Skip duplicates. 285 */ 286 if (strcmp(dmdp->dm_name, mac) == 0) 287 return (DI_WALK_CONTINUE); 288 289 last_dmdp = &dmdp->dm_next; 290 dmdp = dmdp->dm_next; 291 } 292 293 if ((dmdp = malloc(sizeof (*dmdp))) == NULL) 294 return (DI_WALK_CONTINUE); 295 296 (void) strlcpy(dmdp->dm_name, mac, MAXNAMELEN); 297 dmdp->dm_next = NULL; 298 *last_dmdp = dmdp; 299 300 return (DI_WALK_CONTINUE); 301 } 302 303 /* 304 * Invoke the specified callback for each DDI_NT_NET node. 305 */ 306 dladm_status_t 307 dladm_mac_walk(int (*fn)(const char *, void *arg), void *arg) 308 { 309 di_node_t root; 310 dladm_mac_walk_t dmw; 311 dladm_mac_dev_t *dmdp, *next; 312 boolean_t done = B_FALSE; 313 314 if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) 315 return (dladm_errno2status(errno)); 316 317 dmw.dmd_dev_list = NULL; 318 319 (void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, &dmw, 320 i_dladm_mac_walk); 321 322 di_fini(root); 323 324 dmdp = dmw.dmd_dev_list; 325 for (dmdp = dmw.dmd_dev_list; dmdp != NULL; dmdp = next) { 326 next = dmdp->dm_next; 327 if (!done && 328 ((*fn)(dmdp->dm_name, arg) == DLADM_WALK_TERMINATE)) { 329 done = B_TRUE; 330 } 331 free(dmdp); 332 } 333 334 return (DLADM_STATUS_OK); 335 } 336 337 /* 338 * Get the current attributes of the specified datalink. 339 */ 340 dladm_status_t 341 dladm_info(dladm_handle_t handle, datalink_id_t linkid, dladm_attr_t *dap) 342 { 343 return (i_dladm_info(handle, linkid, dap)); 344 } 345 346 const char * 347 dladm_linkstate2str(link_state_t state, char *buf) 348 { 349 const char *s; 350 351 switch (state) { 352 case LINK_STATE_UP: 353 s = "up"; 354 break; 355 case LINK_STATE_DOWN: 356 s = "down"; 357 break; 358 default: 359 s = "unknown"; 360 break; 361 } 362 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 363 return (buf); 364 } 365 366 const char * 367 dladm_linkduplex2str(link_duplex_t duplex, char *buf) 368 { 369 const char *s; 370 371 switch (duplex) { 372 case LINK_DUPLEX_FULL: 373 s = "full"; 374 break; 375 case LINK_DUPLEX_HALF: 376 s = "half"; 377 break; 378 default: 379 s = "unknown"; 380 break; 381 } 382 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 383 return (buf); 384 } 385 386 /* 387 * Case 1: rename an existing link1 to a link2 that does not exist. 388 * Result: <linkid1, link2> 389 */ 390 static dladm_status_t 391 i_dladm_rename_link_c1(dladm_handle_t handle, datalink_id_t linkid1, 392 const char *link1, const char *link2, uint32_t flags) 393 { 394 dld_ioc_rename_t dir; 395 dladm_status_t status = DLADM_STATUS_OK; 396 397 /* 398 * Link is currently available. Check to see whether anything is 399 * holding this link to prevent a rename operation. 400 */ 401 if (flags & DLADM_OPT_ACTIVE) { 402 dir.dir_linkid1 = linkid1; 403 dir.dir_linkid2 = DATALINK_INVALID_LINKID; 404 (void) strlcpy(dir.dir_link, link2, MAXLINKNAMELEN); 405 406 if (ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir) < 0) { 407 status = dladm_errno2status(errno); 408 return (status); 409 } 410 } 411 412 status = dladm_remap_datalink_id(handle, linkid1, link2); 413 if (status != DLADM_STATUS_OK && (flags & DLADM_OPT_ACTIVE)) { 414 (void) strlcpy(dir.dir_link, link1, MAXLINKNAMELEN); 415 (void) ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir); 416 } 417 return (status); 418 } 419 420 typedef struct link_hold_arg_s { 421 datalink_id_t linkid; 422 datalink_id_t holder; 423 uint32_t flags; 424 } link_hold_arg_t; 425 426 static int 427 i_dladm_aggr_link_hold(dladm_handle_t handle, datalink_id_t aggrid, void *arg) 428 { 429 link_hold_arg_t *hold_arg = arg; 430 dladm_aggr_grp_attr_t ginfo; 431 dladm_status_t status; 432 int i; 433 434 status = dladm_aggr_info(handle, aggrid, &ginfo, hold_arg->flags); 435 if (status != DLADM_STATUS_OK) 436 return (DLADM_WALK_CONTINUE); 437 438 for (i = 0; i < ginfo.lg_nports; i++) { 439 if (ginfo.lg_ports[i].lp_linkid == hold_arg->linkid) { 440 hold_arg->holder = aggrid; 441 return (DLADM_WALK_TERMINATE); 442 } 443 } 444 return (DLADM_WALK_CONTINUE); 445 } 446 447 static int 448 i_dladm_vlan_link_hold(dladm_handle_t handle, datalink_id_t vlanid, void *arg) 449 { 450 link_hold_arg_t *hold_arg = arg; 451 dladm_vlan_attr_t vinfo; 452 dladm_status_t status; 453 454 status = dladm_vlan_info(handle, vlanid, &vinfo, hold_arg->flags); 455 if (status != DLADM_STATUS_OK) 456 return (DLADM_WALK_CONTINUE); 457 458 if (vinfo.dv_linkid == hold_arg->linkid) { 459 hold_arg->holder = vlanid; 460 return (DLADM_WALK_TERMINATE); 461 } 462 return (DLADM_WALK_CONTINUE); 463 } 464 465 /* 466 * Case 2: rename an available physical link link1 to a REMOVED physical link 467 * link2. As a result, link1 directly inherits all datalinks configured 468 * over link2 (linkid2). 469 * Result: <linkid2, link2, link1_phymaj, link1_phyinst, link1_devname, 470 * link2_other_attr> 471 */ 472 static dladm_status_t 473 i_dladm_rename_link_c2(dladm_handle_t handle, datalink_id_t linkid1, 474 datalink_id_t linkid2) 475 { 476 rcm_handle_t *rcm_hdl = NULL; 477 nvlist_t *nvl = NULL; 478 link_hold_arg_t arg; 479 dld_ioc_rename_t dir; 480 dladm_conf_t conf1, conf2; 481 char devname[MAXLINKNAMELEN]; 482 uint64_t phymaj, phyinst; 483 dladm_status_t status = DLADM_STATUS_OK; 484 485 /* 486 * First check if linkid1 is associated with any persistent 487 * aggregations or VLANs. If yes, return BUSY. 488 */ 489 arg.linkid = linkid1; 490 arg.holder = DATALINK_INVALID_LINKID; 491 arg.flags = DLADM_OPT_PERSIST; 492 (void) dladm_walk_datalink_id(i_dladm_aggr_link_hold, handle, &arg, 493 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 494 if (arg.holder != DATALINK_INVALID_LINKID) 495 return (DLADM_STATUS_LINKBUSY); 496 497 arg.flags = DLADM_OPT_PERSIST; 498 (void) dladm_walk_datalink_id(i_dladm_vlan_link_hold, handle, &arg, 499 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 500 if (arg.holder != DATALINK_INVALID_LINKID) 501 return (DLADM_STATUS_LINKBUSY); 502 503 /* 504 * Send DLDIOC_RENAME to request to rename link1's linkid to 505 * be linkid2. This will check whether link1 is used by any 506 * aggregations or VLANs, or is held by any application. If yes, 507 * return failure. 508 */ 509 dir.dir_linkid1 = linkid1; 510 dir.dir_linkid2 = linkid2; 511 if (ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir) < 0) 512 status = dladm_errno2status(errno); 513 514 if (status != DLADM_STATUS_OK) { 515 return (status); 516 } 517 518 /* 519 * Now change the phymaj, phyinst and devname associated with linkid1 520 * to be associated with linkid2. Before doing that, the old active 521 * linkprop of linkid1 should be deleted. 522 */ 523 (void) dladm_set_linkprop(handle, linkid1, NULL, NULL, 0, 524 DLADM_OPT_ACTIVE); 525 526 if (((status = dladm_read_conf(handle, linkid1, &conf1)) != 527 DLADM_STATUS_OK) || 528 ((status = dladm_get_conf_field(handle, conf1, FDEVNAME, devname, 529 MAXLINKNAMELEN)) != DLADM_STATUS_OK) || 530 ((status = dladm_get_conf_field(handle, conf1, FPHYMAJ, &phymaj, 531 sizeof (uint64_t))) != DLADM_STATUS_OK) || 532 ((status = dladm_get_conf_field(handle, conf1, FPHYINST, &phyinst, 533 sizeof (uint64_t))) != DLADM_STATUS_OK) || 534 ((status = dladm_read_conf(handle, linkid2, &conf2)) != 535 DLADM_STATUS_OK)) { 536 dir.dir_linkid1 = linkid2; 537 dir.dir_linkid2 = linkid1; 538 (void) dladm_init_linkprop(handle, linkid1, B_FALSE); 539 (void) ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir); 540 return (status); 541 } 542 543 dladm_destroy_conf(handle, conf1); 544 (void) dladm_set_conf_field(handle, conf2, FDEVNAME, DLADM_TYPE_STR, 545 devname); 546 (void) dladm_set_conf_field(handle, conf2, FPHYMAJ, DLADM_TYPE_UINT64, 547 &phymaj); 548 (void) dladm_set_conf_field(handle, conf2, FPHYINST, 549 DLADM_TYPE_UINT64, &phyinst); 550 (void) dladm_write_conf(handle, conf2); 551 dladm_destroy_conf(handle, conf2); 552 553 /* 554 * Delete link1 and mark link2 up. 555 */ 556 (void) dladm_remove_conf(handle, linkid1); 557 (void) dladm_destroy_datalink_id(handle, linkid1, DLADM_OPT_ACTIVE | 558 DLADM_OPT_PERSIST); 559 (void) dladm_up_datalink_id(handle, linkid2); 560 561 /* 562 * Now generate the RCM_RESOURCE_LINK_NEW sysevent which can be 563 * consumed by the RCM framework to restore all the datalink and 564 * IP configuration. 565 */ 566 status = DLADM_STATUS_FAILED; 567 if ((nvlist_alloc(&nvl, 0, 0) != 0) || 568 (nvlist_add_uint64(nvl, RCM_NV_LINKID, linkid2) != 0)) { 569 goto done; 570 } 571 572 if (rcm_alloc_handle(NULL, 0, NULL, &rcm_hdl) != RCM_SUCCESS) 573 goto done; 574 575 if (rcm_notify_event(rcm_hdl, RCM_RESOURCE_LINK_NEW, 0, nvl, NULL) == 576 RCM_SUCCESS) { 577 status = DLADM_STATUS_OK; 578 } 579 580 done: 581 if (rcm_hdl != NULL) 582 (void) rcm_free_handle(rcm_hdl); 583 if (nvl != NULL) 584 nvlist_free(nvl); 585 return (status); 586 } 587 588 /* 589 * case 3: rename a non-existent link to a REMOVED physical link. 590 * Set the removed physical link's device name to link1, so that 591 * when link1 attaches, it inherits all the link configuration of 592 * the removed physical link. 593 */ 594 static dladm_status_t 595 i_dladm_rename_link_c3(dladm_handle_t handle, const char *link1, 596 datalink_id_t linkid2) 597 { 598 dladm_conf_t conf; 599 dladm_status_t status; 600 601 if (!dladm_valid_linkname(link1)) 602 return (DLADM_STATUS_LINKINVAL); 603 604 status = dladm_read_conf(handle, linkid2, &conf); 605 if (status != DLADM_STATUS_OK) 606 goto done; 607 608 if ((status = dladm_set_conf_field(handle, conf, FDEVNAME, 609 DLADM_TYPE_STR, link1)) == DLADM_STATUS_OK) { 610 status = dladm_write_conf(handle, conf); 611 } 612 613 dladm_destroy_conf(handle, conf); 614 615 done: 616 return (status); 617 } 618 619 dladm_status_t 620 dladm_rename_link(dladm_handle_t handle, const char *link1, const char *link2) 621 { 622 datalink_id_t linkid1 = DATALINK_INVALID_LINKID; 623 datalink_id_t linkid2 = DATALINK_INVALID_LINKID; 624 uint32_t flags1, flags2; 625 datalink_class_t class1, class2; 626 uint32_t media1, media2; 627 boolean_t remphy2 = B_FALSE; 628 dladm_status_t status; 629 630 (void) dladm_name2info(handle, link1, &linkid1, &flags1, &class1, 631 &media1); 632 if ((dladm_name2info(handle, link2, &linkid2, &flags2, &class2, 633 &media2) == DLADM_STATUS_OK) && (class2 == DATALINK_CLASS_PHYS) && 634 (flags2 == DLADM_OPT_PERSIST)) { 635 /* 636 * see whether link2 is a removed physical link. 637 */ 638 remphy2 = B_TRUE; 639 } 640 641 if (linkid1 != DATALINK_INVALID_LINKID) { 642 if (linkid2 == DATALINK_INVALID_LINKID) { 643 /* 644 * case 1: rename an existing link to a link that 645 * does not exist. 646 */ 647 status = i_dladm_rename_link_c1(handle, linkid1, link1, 648 link2, flags1); 649 } else if (remphy2) { 650 /* 651 * case 2: rename an available link to a REMOVED 652 * physical link. Return failure if link1 is not 653 * an active physical link. 654 */ 655 if ((class1 != class2) || (media1 != media2) || 656 !(flags1 & DLADM_OPT_ACTIVE)) { 657 status = DLADM_STATUS_BADARG; 658 } else { 659 status = i_dladm_rename_link_c2(handle, linkid1, 660 linkid2); 661 } 662 } else { 663 status = DLADM_STATUS_EXIST; 664 } 665 } else if (remphy2) { 666 status = i_dladm_rename_link_c3(handle, link1, linkid2); 667 } else { 668 status = DLADM_STATUS_NOTFOUND; 669 } 670 return (status); 671 } 672 673 typedef struct consumer_del_phys_arg_s { 674 datalink_id_t linkid; 675 } consumer_del_phys_arg_t; 676 677 static int 678 i_dladm_vlan_link_del(dladm_handle_t handle, datalink_id_t vlanid, void *arg) 679 { 680 consumer_del_phys_arg_t *del_arg = arg; 681 dladm_vlan_attr_t vinfo; 682 dladm_status_t status; 683 684 status = dladm_vlan_info(handle, vlanid, &vinfo, DLADM_OPT_PERSIST); 685 if (status != DLADM_STATUS_OK) 686 return (DLADM_WALK_CONTINUE); 687 688 if (vinfo.dv_linkid == del_arg->linkid) 689 (void) dladm_vlan_delete(handle, vlanid, DLADM_OPT_PERSIST); 690 return (DLADM_WALK_CONTINUE); 691 } 692 693 static int 694 i_dladm_part_link_del(dladm_handle_t handle, datalink_id_t partid, void *arg) 695 { 696 consumer_del_phys_arg_t *del_arg = arg; 697 dladm_part_attr_t pinfo; 698 dladm_status_t status; 699 700 status = dladm_part_info(handle, partid, &pinfo, DLADM_OPT_PERSIST); 701 if (status != DLADM_STATUS_OK) 702 return (DLADM_WALK_CONTINUE); 703 704 if (pinfo.dia_physlinkid == del_arg->linkid) 705 (void) dladm_part_delete(handle, partid, DLADM_OPT_PERSIST); 706 return (DLADM_WALK_CONTINUE); 707 } 708 709 static int 710 i_dladm_aggr_link_del(dladm_handle_t handle, datalink_id_t aggrid, void *arg) 711 { 712 consumer_del_phys_arg_t *del_arg = arg; 713 dladm_aggr_grp_attr_t ginfo; 714 dladm_status_t status; 715 dladm_aggr_port_attr_db_t port[1]; 716 int i; 717 718 status = dladm_aggr_info(handle, aggrid, &ginfo, DLADM_OPT_PERSIST); 719 if (status != DLADM_STATUS_OK) 720 return (DLADM_WALK_CONTINUE); 721 722 for (i = 0; i < ginfo.lg_nports; i++) 723 if (ginfo.lg_ports[i].lp_linkid == del_arg->linkid) 724 break; 725 726 if (i != ginfo.lg_nports) { 727 if (ginfo.lg_nports == 1 && i == 0) { 728 consumer_del_phys_arg_t aggr_del_arg; 729 730 /* 731 * First delete all the VLANs on this aggregation, then 732 * delete the aggregation itself. 733 */ 734 aggr_del_arg.linkid = aggrid; 735 (void) dladm_walk_datalink_id(i_dladm_vlan_link_del, 736 handle, &aggr_del_arg, DATALINK_CLASS_VLAN, 737 DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 738 (void) dladm_aggr_delete(handle, aggrid, 739 DLADM_OPT_PERSIST); 740 } else { 741 port[0].lp_linkid = del_arg->linkid; 742 (void) dladm_aggr_remove(handle, aggrid, 1, port, 743 DLADM_OPT_PERSIST); 744 } 745 } 746 return (DLADM_WALK_CONTINUE); 747 } 748 749 typedef struct del_phys_arg_s { 750 dladm_status_t rval; 751 } del_phys_arg_t; 752 753 static int 754 i_dladm_phys_delete(dladm_handle_t handle, datalink_id_t linkid, void *arg) 755 { 756 uint32_t flags; 757 datalink_class_t class; 758 uint32_t media; 759 dladm_status_t status = DLADM_STATUS_OK; 760 del_phys_arg_t *del_phys_arg = arg; 761 consumer_del_phys_arg_t del_arg; 762 763 if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class, 764 &media, NULL, 0)) != DLADM_STATUS_OK) { 765 goto done; 766 } 767 768 /* 769 * see whether this link is a removed physical link. 770 */ 771 if ((class != DATALINK_CLASS_PHYS) || !(flags & DLADM_OPT_PERSIST) || 772 (flags & DLADM_OPT_ACTIVE)) { 773 status = DLADM_STATUS_BADARG; 774 goto done; 775 } 776 777 if (media == DL_ETHER) { 778 del_arg.linkid = linkid; 779 (void) dladm_walk_datalink_id(i_dladm_aggr_link_del, handle, 780 &del_arg, DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, 781 DLADM_OPT_PERSIST); 782 (void) dladm_walk_datalink_id(i_dladm_vlan_link_del, handle, 783 &del_arg, DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, 784 DLADM_OPT_PERSIST); 785 } else if (media == DL_IB) { 786 del_arg.linkid = linkid; 787 (void) dladm_walk_datalink_id(i_dladm_part_link_del, handle, 788 &del_arg, DATALINK_CLASS_PART, DL_IB, DLADM_OPT_PERSIST); 789 } 790 791 (void) dladm_remove_conf(handle, linkid); 792 (void) dladm_destroy_datalink_id(handle, linkid, DLADM_OPT_PERSIST); 793 done: 794 del_phys_arg->rval = status; 795 return (DLADM_WALK_CONTINUE); 796 } 797 798 dladm_status_t 799 dladm_phys_delete(dladm_handle_t handle, datalink_id_t linkid) 800 { 801 del_phys_arg_t arg = {DLADM_STATUS_OK}; 802 803 if (linkid == DATALINK_ALL_LINKID) { 804 (void) dladm_walk_datalink_id(i_dladm_phys_delete, handle, &arg, 805 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, 806 DLADM_OPT_PERSIST); 807 return (DLADM_STATUS_OK); 808 } else { 809 (void) i_dladm_phys_delete(handle, linkid, &arg); 810 return (arg.rval); 811 } 812 } 813 814 dladm_status_t 815 dladm_phys_info(dladm_handle_t handle, datalink_id_t linkid, 816 dladm_phys_attr_t *dpap, uint32_t flags) 817 { 818 dladm_status_t status; 819 820 assert(flags == DLADM_OPT_ACTIVE || flags == DLADM_OPT_PERSIST); 821 822 switch (flags) { 823 case DLADM_OPT_PERSIST: { 824 dladm_conf_t conf; 825 826 status = dladm_read_conf(handle, linkid, &conf); 827 if (status != DLADM_STATUS_OK) 828 return (status); 829 830 status = dladm_get_conf_field(handle, conf, FDEVNAME, 831 dpap->dp_dev, MAXLINKNAMELEN); 832 dladm_destroy_conf(handle, conf); 833 return (status); 834 } 835 case DLADM_OPT_ACTIVE: { 836 dld_ioc_phys_attr_t dip; 837 838 dip.dip_linkid = linkid; 839 if (ioctl(dladm_dld_fd(handle), DLDIOC_PHYS_ATTR, &dip) < 0) { 840 status = dladm_errno2status(errno); 841 return (status); 842 } 843 dpap->dp_novanity = dip.dip_novanity; 844 (void) strlcpy(dpap->dp_dev, dip.dip_dev, MAXLINKNAMELEN); 845 return (DLADM_STATUS_OK); 846 } 847 default: 848 return (DLADM_STATUS_BADARG); 849 } 850 } 851 852 typedef struct i_walk_dev_state_s { 853 const char *devname; 854 datalink_id_t linkid; 855 boolean_t found; 856 } i_walk_dev_state_t; 857 858 int 859 i_dladm_walk_dev2linkid(dladm_handle_t handle, datalink_id_t linkid, void *arg) 860 { 861 dladm_phys_attr_t dpa; 862 dladm_status_t status; 863 i_walk_dev_state_t *statep = arg; 864 865 status = dladm_phys_info(handle, linkid, &dpa, DLADM_OPT_PERSIST); 866 if ((status == DLADM_STATUS_OK) && 867 (strcmp(statep->devname, dpa.dp_dev) == 0)) { 868 statep->found = B_TRUE; 869 statep->linkid = linkid; 870 return (DLADM_WALK_TERMINATE); 871 } 872 return (DLADM_WALK_CONTINUE); 873 } 874 875 /* 876 * Get the linkid from the physical device name. 877 */ 878 dladm_status_t 879 dladm_dev2linkid(dladm_handle_t handle, const char *devname, 880 datalink_id_t *linkidp) 881 { 882 i_walk_dev_state_t state; 883 884 state.found = B_FALSE; 885 state.devname = devname; 886 887 (void) dladm_walk_datalink_id(i_dladm_walk_dev2linkid, handle, &state, 888 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 889 if (state.found == B_TRUE) { 890 *linkidp = state.linkid; 891 return (DLADM_STATUS_OK); 892 } else { 893 return (dladm_errno2status(ENOENT)); 894 } 895 } 896 897 static int 898 parse_devname(const char *devname, char *driver, uint_t *ppa, size_t maxlen) 899 { 900 char *cp, *tp; 901 int len; 902 903 /* 904 * device name length must not be 0, and it must end with digit. 905 */ 906 if (((len = strlen(devname)) == 0) || !isdigit(devname[len - 1])) 907 return (EINVAL); 908 909 (void) strlcpy(driver, devname, maxlen); 910 cp = (char *)&driver[len - 1]; 911 912 for (tp = cp; isdigit(*tp); tp--) { 913 if (tp <= driver) 914 return (EINVAL); 915 } 916 917 *ppa = atoi(tp + 1); 918 *(tp + 1) = '\0'; 919 return (0); 920 } 921 922 dladm_status_t 923 dladm_linkid2legacyname(dladm_handle_t handle, datalink_id_t linkid, char *dev, 924 size_t len) 925 { 926 char devname[MAXLINKNAMELEN]; 927 uint16_t vid = VLAN_ID_NONE; 928 datalink_class_t class; 929 dladm_status_t status; 930 931 status = dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, 932 NULL, 0); 933 if (status != DLADM_STATUS_OK) 934 goto done; 935 936 /* 937 * If this is a VLAN, we must first determine the class and linkid of 938 * the link the VLAN has been created over. 939 */ 940 if (class == DATALINK_CLASS_VLAN) { 941 dladm_vlan_attr_t dva; 942 943 status = dladm_vlan_info(handle, linkid, &dva, 944 DLADM_OPT_ACTIVE); 945 if (status != DLADM_STATUS_OK) 946 goto done; 947 linkid = dva.dv_linkid; 948 vid = dva.dv_vid; 949 950 if ((status = dladm_datalink_id2info(handle, linkid, NULL, 951 &class, NULL, NULL, 0)) != DLADM_STATUS_OK) { 952 goto done; 953 } 954 } 955 956 switch (class) { 957 case DATALINK_CLASS_AGGR: { 958 dladm_aggr_grp_attr_t dga; 959 960 status = dladm_aggr_info(handle, linkid, &dga, 961 DLADM_OPT_ACTIVE); 962 if (status != DLADM_STATUS_OK) 963 goto done; 964 965 if (dga.lg_key == 0) { 966 /* 967 * If the key was not specified when the aggregation 968 * is created, we cannot guess its /dev node name. 969 */ 970 status = DLADM_STATUS_BADARG; 971 goto done; 972 } 973 (void) snprintf(devname, MAXLINKNAMELEN, "aggr%d", dga.lg_key); 974 break; 975 } 976 case DATALINK_CLASS_PHYS: { 977 dladm_phys_attr_t dpa; 978 979 status = dladm_phys_info(handle, linkid, &dpa, 980 DLADM_OPT_PERSIST); 981 if (status != DLADM_STATUS_OK) 982 goto done; 983 984 (void) strlcpy(devname, dpa.dp_dev, MAXLINKNAMELEN); 985 break; 986 } 987 default: 988 status = DLADM_STATUS_BADARG; 989 goto done; 990 } 991 992 if (vid != VLAN_ID_NONE) { 993 char drv[MAXNAMELEN]; 994 uint_t ppa; 995 996 if (parse_devname(devname, drv, &ppa, MAXNAMELEN) != 0) { 997 status = DLADM_STATUS_BADARG; 998 goto done; 999 } 1000 if (snprintf(dev, len, "%s%d", drv, vid * 1000 + ppa) >= len) 1001 status = DLADM_STATUS_TOOSMALL; 1002 } else { 1003 if (strlcpy(dev, devname, len) >= len) 1004 status = DLADM_STATUS_TOOSMALL; 1005 } 1006 1007 done: 1008 return (status); 1009 } 1010 1011 dladm_status_t 1012 dladm_parselink(const char *dev, char *provider, uint_t *ppa) 1013 { 1014 ifspec_t ifsp; 1015 1016 if (dev == NULL || !ifparse_ifspec(dev, &ifsp)) 1017 return (DLADM_STATUS_LINKINVAL); 1018 1019 if (provider != NULL) 1020 (void) strlcpy(provider, ifsp.ifsp_devnm, DLPI_LINKNAME_MAX); 1021 1022 if (ppa != NULL) 1023 *ppa = ifsp.ifsp_ppa; 1024 1025 return (DLADM_STATUS_OK); 1026 } 1027