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