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> 46e7801d59Ssowmini #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 /* 255811fc8e1Syz147064 * Set zoneid of a given link. Note that this function takes a link name 256811fc8e1Syz147064 * argument instead of a linkid, because a data-link (and its linkid) could 257811fc8e1Syz147064 * be created implicitly as the result of this function. For example, a VLAN 258811fc8e1Syz147064 * could be created if a VLAN PPA hack name is assigned to an exclusive 259811fc8e1Syz147064 * non-global zone. 260f595a68aSyz147064 */ 261d62bc4baSyz147064 dladm_status_t 262d62bc4baSyz147064 dladm_setzid(const char *link, zoneid_t zoneid) 263f595a68aSyz147064 { 264d62bc4baSyz147064 int fd; 265d62bc4baSyz147064 dladm_status_t status = DLADM_STATUS_OK; 266d62bc4baSyz147064 dld_ioc_setzid_t dis; 267d62bc4baSyz147064 268d62bc4baSyz147064 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 269d62bc4baSyz147064 return (dladm_errno2status(errno)); 270d62bc4baSyz147064 271d62bc4baSyz147064 bzero(&dis, sizeof (dld_ioc_setzid_t)); 272d62bc4baSyz147064 (void) strlcpy(dis.dis_link, link, MAXLINKNAMELEN); 273d62bc4baSyz147064 dis.dis_zid = zoneid; 274d62bc4baSyz147064 275d62bc4baSyz147064 if (i_dladm_ioctl(fd, DLDIOC_SETZID, &dis, sizeof (dis)) < 0) 276d62bc4baSyz147064 status = dladm_errno2status(errno); 277d62bc4baSyz147064 278d62bc4baSyz147064 (void) close(fd); 279d62bc4baSyz147064 return (status); 280f595a68aSyz147064 } 281f595a68aSyz147064 282f595a68aSyz147064 /* 283d62bc4baSyz147064 * Get zoneid of a given link 284f595a68aSyz147064 */ 285d62bc4baSyz147064 dladm_status_t 286d62bc4baSyz147064 dladm_getzid(datalink_id_t linkid, zoneid_t *zoneidp) 287f595a68aSyz147064 { 288d62bc4baSyz147064 int fd; 289d62bc4baSyz147064 dladm_status_t status = DLADM_STATUS_OK; 290d62bc4baSyz147064 dld_ioc_getzid_t dig; 291d62bc4baSyz147064 292d62bc4baSyz147064 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 293d62bc4baSyz147064 return (dladm_errno2status(errno)); 294d62bc4baSyz147064 295d62bc4baSyz147064 bzero(&dig, sizeof (dld_ioc_getzid_t)); 296d62bc4baSyz147064 dig.dig_linkid = linkid; 297d62bc4baSyz147064 dig.dig_zid = -1; 298d62bc4baSyz147064 299d62bc4baSyz147064 if (i_dladm_ioctl(fd, DLDIOC_GETZID, &dig, sizeof (dig)) < 0) 300d62bc4baSyz147064 status = dladm_errno2status(errno); 301d62bc4baSyz147064 302d62bc4baSyz147064 (void) close(fd); 303d62bc4baSyz147064 304d62bc4baSyz147064 if (status == DLADM_STATUS_OK) 305d62bc4baSyz147064 *zoneidp = dig.dig_zid; 306d62bc4baSyz147064 307d62bc4baSyz147064 return (status); 308d62bc4baSyz147064 } 309d62bc4baSyz147064 310d62bc4baSyz147064 /* 311d62bc4baSyz147064 * Case 1: rename an existing link1 to a link2 that does not exist. 312d62bc4baSyz147064 * Result: <linkid1, link2> 313d62bc4baSyz147064 */ 314d62bc4baSyz147064 static dladm_status_t 315d62bc4baSyz147064 i_dladm_rename_link_c1(datalink_id_t linkid1, const char *link1, 316d62bc4baSyz147064 const char *link2, uint32_t flags) 317d62bc4baSyz147064 { 318d62bc4baSyz147064 dld_ioc_rename_t dir; 319d62bc4baSyz147064 dladm_conf_t conf; 320d62bc4baSyz147064 dladm_status_t status = DLADM_STATUS_OK; 321d62bc4baSyz147064 int fd; 322d62bc4baSyz147064 323d62bc4baSyz147064 /* 324d62bc4baSyz147064 * Link is currently available. Check to see whether anything is 325d62bc4baSyz147064 * holding this link to prevent a rename operation. 326d62bc4baSyz147064 */ 327d62bc4baSyz147064 if (flags & DLADM_OPT_ACTIVE) { 328d62bc4baSyz147064 dir.dir_linkid1 = linkid1; 329d62bc4baSyz147064 dir.dir_linkid2 = DATALINK_INVALID_LINKID; 330d62bc4baSyz147064 (void) strlcpy(dir.dir_link, link2, MAXLINKNAMELEN); 331d62bc4baSyz147064 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 332d62bc4baSyz147064 return (dladm_errno2status(errno)); 333d62bc4baSyz147064 334d62bc4baSyz147064 if (i_dladm_ioctl(fd, DLDIOC_RENAME, &dir, sizeof (dir)) < 0) { 335d62bc4baSyz147064 status = dladm_errno2status(errno); 336d62bc4baSyz147064 (void) close(fd); 337d62bc4baSyz147064 return (status); 338d62bc4baSyz147064 } 339d62bc4baSyz147064 } 340d62bc4baSyz147064 341d62bc4baSyz147064 status = dladm_remap_datalink_id(linkid1, link2); 342d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 343d62bc4baSyz147064 goto done; 344d62bc4baSyz147064 345d62bc4baSyz147064 /* 346d62bc4baSyz147064 * Flush the current mapping to persistent configuration. 347d62bc4baSyz147064 */ 348d62bc4baSyz147064 if ((flags & DLADM_OPT_PERSIST) && 349d62bc4baSyz147064 (((status = dladm_read_conf(linkid1, &conf)) != DLADM_STATUS_OK) || 350d62bc4baSyz147064 ((status = dladm_write_conf(conf)) != DLADM_STATUS_OK))) { 351d62bc4baSyz147064 (void) dladm_remap_datalink_id(linkid1, link1); 352d62bc4baSyz147064 } 353d62bc4baSyz147064 done: 354d62bc4baSyz147064 if (flags & DLADM_OPT_ACTIVE) { 355d62bc4baSyz147064 if (status != DLADM_STATUS_OK) { 356d62bc4baSyz147064 (void) strlcpy(dir.dir_link, link1, MAXLINKNAMELEN); 357d62bc4baSyz147064 (void) i_dladm_ioctl(fd, DLDIOC_RENAME, &dir, 358d62bc4baSyz147064 sizeof (dir)); 359d62bc4baSyz147064 } 360d62bc4baSyz147064 (void) close(fd); 361d62bc4baSyz147064 } 362d62bc4baSyz147064 return (status); 363d62bc4baSyz147064 } 364d62bc4baSyz147064 365d62bc4baSyz147064 typedef struct link_hold_arg_s { 366d62bc4baSyz147064 datalink_id_t linkid; 367d62bc4baSyz147064 datalink_id_t holder; 368d62bc4baSyz147064 uint32_t flags; 369d62bc4baSyz147064 } link_hold_arg_t; 370d62bc4baSyz147064 371d62bc4baSyz147064 static int 372d62bc4baSyz147064 i_dladm_aggr_link_hold(datalink_id_t aggrid, void *arg) 373d62bc4baSyz147064 { 374d62bc4baSyz147064 link_hold_arg_t *hold_arg = arg; 375d62bc4baSyz147064 dladm_aggr_grp_attr_t ginfo; 376d62bc4baSyz147064 dladm_status_t status; 377d62bc4baSyz147064 int i; 378d62bc4baSyz147064 379d62bc4baSyz147064 status = dladm_aggr_info(aggrid, &ginfo, hold_arg->flags); 380d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 381d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 382d62bc4baSyz147064 383d62bc4baSyz147064 for (i = 0; i < ginfo.lg_nports; i++) { 384d62bc4baSyz147064 if (ginfo.lg_ports[i].lp_linkid == hold_arg->linkid) { 385d62bc4baSyz147064 hold_arg->holder = aggrid; 386d62bc4baSyz147064 return (DLADM_WALK_TERMINATE); 387d62bc4baSyz147064 } 388d62bc4baSyz147064 } 389d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 390d62bc4baSyz147064 } 391d62bc4baSyz147064 392d62bc4baSyz147064 static int 393d62bc4baSyz147064 i_dladm_vlan_link_hold(datalink_id_t vlanid, void *arg) 394d62bc4baSyz147064 { 395d62bc4baSyz147064 link_hold_arg_t *hold_arg = arg; 396d62bc4baSyz147064 dladm_vlan_attr_t vinfo; 397d62bc4baSyz147064 dladm_status_t status; 398d62bc4baSyz147064 399d62bc4baSyz147064 status = dladm_vlan_info(vlanid, &vinfo, hold_arg->flags); 400d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 401d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 402d62bc4baSyz147064 403d62bc4baSyz147064 if (vinfo.dv_linkid == hold_arg->linkid) { 404d62bc4baSyz147064 hold_arg->holder = vlanid; 405d62bc4baSyz147064 return (DLADM_WALK_TERMINATE); 406d62bc4baSyz147064 } 407d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 408d62bc4baSyz147064 } 409d62bc4baSyz147064 410d62bc4baSyz147064 /* 411d62bc4baSyz147064 * Case 2: rename an available physical link link1 to a REMOVED physical link 412d62bc4baSyz147064 * link2. As a result, link1 directly inherits all datalinks configured 413d62bc4baSyz147064 * over link2 (linkid2). 414d62bc4baSyz147064 * Result: <linkid2, link2, link1_phymaj, link1_phyinst, link1_devname, 415d62bc4baSyz147064 * link2_other_attr> 416d62bc4baSyz147064 */ 417d62bc4baSyz147064 static dladm_status_t 418d62bc4baSyz147064 i_dladm_rename_link_c2(datalink_id_t linkid1, datalink_id_t linkid2) 419d62bc4baSyz147064 { 420d62bc4baSyz147064 rcm_handle_t *rcm_hdl = NULL; 421d62bc4baSyz147064 nvlist_t *nvl = NULL; 422d62bc4baSyz147064 link_hold_arg_t arg; 423d62bc4baSyz147064 dld_ioc_rename_t dir; 424d62bc4baSyz147064 int fd; 425d62bc4baSyz147064 dladm_conf_t conf1, conf2; 426d62bc4baSyz147064 char devname[MAXLINKNAMELEN]; 427d62bc4baSyz147064 uint64_t phymaj, phyinst; 428d62bc4baSyz147064 dladm_status_t status = DLADM_STATUS_OK; 429d62bc4baSyz147064 430d62bc4baSyz147064 /* 431d62bc4baSyz147064 * First check if linkid1 is associated with any persistent 432d62bc4baSyz147064 * aggregations or VLANs. If yes, return BUSY. 433d62bc4baSyz147064 */ 434d62bc4baSyz147064 arg.linkid = linkid1; 435d62bc4baSyz147064 arg.holder = DATALINK_INVALID_LINKID; 436d62bc4baSyz147064 arg.flags = DLADM_OPT_PERSIST; 437d62bc4baSyz147064 (void) dladm_walk_datalink_id(i_dladm_aggr_link_hold, &arg, 438d62bc4baSyz147064 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 439d62bc4baSyz147064 if (arg.holder != DATALINK_INVALID_LINKID) 440d62bc4baSyz147064 return (DLADM_STATUS_LINKBUSY); 441d62bc4baSyz147064 442d62bc4baSyz147064 arg.flags = DLADM_OPT_PERSIST; 443d62bc4baSyz147064 (void) dladm_walk_datalink_id(i_dladm_vlan_link_hold, &arg, 444d62bc4baSyz147064 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 445d62bc4baSyz147064 if (arg.holder != DATALINK_INVALID_LINKID) 446d62bc4baSyz147064 return (DLADM_STATUS_LINKBUSY); 447d62bc4baSyz147064 448d62bc4baSyz147064 /* 449d62bc4baSyz147064 * Send DLDIOC_RENAME to request to rename link1's linkid to 450d62bc4baSyz147064 * be linkid2. This will check whether link1 is used by any 451d62bc4baSyz147064 * aggregations or VLANs, or is held by any application. If yes, 452d62bc4baSyz147064 * return failure. 453d62bc4baSyz147064 */ 454d62bc4baSyz147064 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 455d62bc4baSyz147064 return (dladm_errno2status(errno)); 456d62bc4baSyz147064 457d62bc4baSyz147064 dir.dir_linkid1 = linkid1; 458d62bc4baSyz147064 dir.dir_linkid2 = linkid2; 459d62bc4baSyz147064 if (i_dladm_ioctl(fd, DLDIOC_RENAME, &dir, sizeof (dir)) < 0) 460d62bc4baSyz147064 status = dladm_errno2status(errno); 461d62bc4baSyz147064 462d62bc4baSyz147064 if (status != DLADM_STATUS_OK) { 463d62bc4baSyz147064 (void) close(fd); 464d62bc4baSyz147064 return (status); 465d62bc4baSyz147064 } 466d62bc4baSyz147064 467d62bc4baSyz147064 /* 468d62bc4baSyz147064 * Now change the phymaj, phyinst and devname associated with linkid1 469d62bc4baSyz147064 * to be associated with linkid2. Before doing that, the old active 470d62bc4baSyz147064 * linkprop of linkid1 should be deleted. 471d62bc4baSyz147064 */ 472d62bc4baSyz147064 (void) dladm_set_linkprop(linkid1, NULL, NULL, 0, DLADM_OPT_ACTIVE); 473d62bc4baSyz147064 474d62bc4baSyz147064 if (((status = dladm_read_conf(linkid1, &conf1)) != DLADM_STATUS_OK) || 475d62bc4baSyz147064 ((status = dladm_get_conf_field(conf1, FDEVNAME, devname, 476d62bc4baSyz147064 MAXLINKNAMELEN)) != DLADM_STATUS_OK) || 477d62bc4baSyz147064 ((status = dladm_get_conf_field(conf1, FPHYMAJ, &phymaj, 478d62bc4baSyz147064 sizeof (uint64_t))) != DLADM_STATUS_OK) || 479d62bc4baSyz147064 ((status = dladm_get_conf_field(conf1, FPHYINST, &phyinst, 480d62bc4baSyz147064 sizeof (uint64_t))) != DLADM_STATUS_OK) || 481d62bc4baSyz147064 ((status = dladm_read_conf(linkid2, &conf2)) != DLADM_STATUS_OK)) { 482d62bc4baSyz147064 dir.dir_linkid1 = linkid2; 483d62bc4baSyz147064 dir.dir_linkid2 = linkid1; 484*30890389Sartem (void) dladm_init_linkprop(linkid1, B_FALSE); 485d62bc4baSyz147064 (void) i_dladm_ioctl(fd, DLDIOC_RENAME, &dir, sizeof (dir)); 486d62bc4baSyz147064 (void) close(fd); 487d62bc4baSyz147064 return (status); 488d62bc4baSyz147064 } 489d62bc4baSyz147064 (void) close(fd); 490d62bc4baSyz147064 491d62bc4baSyz147064 dladm_destroy_conf(conf1); 492d62bc4baSyz147064 (void) dladm_set_conf_field(conf2, FDEVNAME, DLADM_TYPE_STR, devname); 493d62bc4baSyz147064 (void) dladm_set_conf_field(conf2, FPHYMAJ, DLADM_TYPE_UINT64, &phymaj); 494d62bc4baSyz147064 (void) dladm_set_conf_field(conf2, FPHYINST, 495d62bc4baSyz147064 DLADM_TYPE_UINT64, &phyinst); 496d62bc4baSyz147064 (void) dladm_write_conf(conf2); 497d62bc4baSyz147064 dladm_destroy_conf(conf2); 498d62bc4baSyz147064 499d62bc4baSyz147064 /* 500d62bc4baSyz147064 * Delete link1 and mark link2 up. 501d62bc4baSyz147064 */ 502d62bc4baSyz147064 (void) dladm_destroy_datalink_id(linkid1, DLADM_OPT_ACTIVE | 503d62bc4baSyz147064 DLADM_OPT_PERSIST); 504d62bc4baSyz147064 (void) dladm_remove_conf(linkid1); 505d62bc4baSyz147064 (void) dladm_up_datalink_id(linkid2); 506d62bc4baSyz147064 507d62bc4baSyz147064 /* 508d62bc4baSyz147064 * Now generate the RCM_RESOURCE_LINK_NEW sysevent which can be 509d62bc4baSyz147064 * consumed by the RCM framework to restore all the datalink and 510d62bc4baSyz147064 * IP configuration. 511d62bc4baSyz147064 */ 512d62bc4baSyz147064 status = DLADM_STATUS_FAILED; 513d62bc4baSyz147064 if ((nvlist_alloc(&nvl, 0, 0) != 0) || 514d62bc4baSyz147064 (nvlist_add_uint64(nvl, RCM_NV_LINKID, linkid2) != 0)) { 515d62bc4baSyz147064 goto done; 516d62bc4baSyz147064 } 517d62bc4baSyz147064 518d62bc4baSyz147064 if (rcm_alloc_handle(NULL, 0, NULL, &rcm_hdl) != RCM_SUCCESS) 519d62bc4baSyz147064 goto done; 520d62bc4baSyz147064 521d62bc4baSyz147064 if (rcm_notify_event(rcm_hdl, RCM_RESOURCE_LINK_NEW, 0, nvl, NULL) == 522d62bc4baSyz147064 RCM_SUCCESS) { 523d62bc4baSyz147064 status = DLADM_STATUS_OK; 524d62bc4baSyz147064 } 525d62bc4baSyz147064 526d62bc4baSyz147064 done: 527d62bc4baSyz147064 if (rcm_hdl != NULL) 528d62bc4baSyz147064 (void) rcm_free_handle(rcm_hdl); 529d62bc4baSyz147064 if (nvl != NULL) 530d62bc4baSyz147064 nvlist_free(nvl); 531d62bc4baSyz147064 return (status); 532d62bc4baSyz147064 } 533d62bc4baSyz147064 534d62bc4baSyz147064 /* 535d62bc4baSyz147064 * case 3: rename a non-existent link to a REMOVED physical link. 536d62bc4baSyz147064 * Set the removed physical link's device name to link1, so that 537d62bc4baSyz147064 * when link1 attaches, it inherits all the link configuration of 538d62bc4baSyz147064 * the removed physical link. 539d62bc4baSyz147064 */ 540d62bc4baSyz147064 static dladm_status_t 541d62bc4baSyz147064 i_dladm_rename_link_c3(const char *link1, datalink_id_t linkid2) 542d62bc4baSyz147064 { 543d62bc4baSyz147064 dladm_conf_t conf; 544d62bc4baSyz147064 dladm_status_t status; 545d62bc4baSyz147064 546d62bc4baSyz147064 if (!dladm_valid_linkname(link1)) 547d62bc4baSyz147064 return (DLADM_STATUS_LINKINVAL); 548d62bc4baSyz147064 549d62bc4baSyz147064 status = dladm_read_conf(linkid2, &conf); 550d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 551d62bc4baSyz147064 goto done; 552d62bc4baSyz147064 553d62bc4baSyz147064 if ((status = dladm_set_conf_field(conf, FDEVNAME, DLADM_TYPE_STR, 554d62bc4baSyz147064 link1)) == DLADM_STATUS_OK) { 555d62bc4baSyz147064 status = dladm_write_conf(conf); 556d62bc4baSyz147064 } 557d62bc4baSyz147064 558d62bc4baSyz147064 dladm_destroy_conf(conf); 559d62bc4baSyz147064 560d62bc4baSyz147064 done: 561d62bc4baSyz147064 return (status); 562d62bc4baSyz147064 } 563d62bc4baSyz147064 564d62bc4baSyz147064 dladm_status_t 565d62bc4baSyz147064 dladm_rename_link(const char *link1, const char *link2) 566d62bc4baSyz147064 { 567d62bc4baSyz147064 datalink_id_t linkid1 = DATALINK_INVALID_LINKID; 568d62bc4baSyz147064 datalink_id_t linkid2 = DATALINK_INVALID_LINKID; 569d62bc4baSyz147064 uint32_t flags1, flags2; 570d62bc4baSyz147064 datalink_class_t class1, class2; 571d62bc4baSyz147064 uint32_t media1, media2; 572d62bc4baSyz147064 boolean_t remphy2 = B_FALSE; 573d62bc4baSyz147064 dladm_status_t status; 574d62bc4baSyz147064 575d62bc4baSyz147064 (void) dladm_name2info(link1, &linkid1, &flags1, &class1, &media1); 576d62bc4baSyz147064 if ((dladm_name2info(link2, &linkid2, &flags2, &class2, &media2) == 577d62bc4baSyz147064 DLADM_STATUS_OK) && (class2 == DATALINK_CLASS_PHYS) && 578d62bc4baSyz147064 (flags2 == DLADM_OPT_PERSIST)) { 579d62bc4baSyz147064 /* 580d62bc4baSyz147064 * see whether link2 is a removed physical link. 581d62bc4baSyz147064 */ 582d62bc4baSyz147064 remphy2 = B_TRUE; 583d62bc4baSyz147064 } 584d62bc4baSyz147064 585d62bc4baSyz147064 if (linkid1 != DATALINK_INVALID_LINKID) { 586d62bc4baSyz147064 if (linkid2 == DATALINK_INVALID_LINKID) { 587d62bc4baSyz147064 /* 588d62bc4baSyz147064 * case 1: rename an existing link to a link that 589d62bc4baSyz147064 * does not exist. 590d62bc4baSyz147064 */ 591d62bc4baSyz147064 status = i_dladm_rename_link_c1(linkid1, link1, link2, 592d62bc4baSyz147064 flags1); 593d62bc4baSyz147064 } else if (remphy2) { 594d62bc4baSyz147064 /* 595d62bc4baSyz147064 * case 2: rename an available link to a REMOVED 596d62bc4baSyz147064 * physical link. Return failure if link1 is not 597d62bc4baSyz147064 * an active physical link. 598d62bc4baSyz147064 */ 599d62bc4baSyz147064 if ((class1 != class2) || (media1 != media2) || 600d62bc4baSyz147064 !(flags1 & DLADM_OPT_ACTIVE)) { 601d62bc4baSyz147064 status = DLADM_STATUS_BADARG; 602d62bc4baSyz147064 } else { 603d62bc4baSyz147064 status = i_dladm_rename_link_c2(linkid1, 604d62bc4baSyz147064 linkid2); 605d62bc4baSyz147064 } 606d62bc4baSyz147064 } else { 607d62bc4baSyz147064 status = DLADM_STATUS_EXIST; 608d62bc4baSyz147064 } 609d62bc4baSyz147064 } else if (remphy2) { 610d62bc4baSyz147064 status = i_dladm_rename_link_c3(link1, linkid2); 611d62bc4baSyz147064 } else { 612d62bc4baSyz147064 status = DLADM_STATUS_NOTFOUND; 613d62bc4baSyz147064 } 614d62bc4baSyz147064 return (status); 615d62bc4baSyz147064 } 616d62bc4baSyz147064 617d62bc4baSyz147064 typedef struct consumer_del_phys_arg_s { 618d62bc4baSyz147064 datalink_id_t linkid; 619d62bc4baSyz147064 } consumer_del_phys_arg_t; 620d62bc4baSyz147064 621d62bc4baSyz147064 static int 622d62bc4baSyz147064 i_dladm_vlan_link_del(datalink_id_t vlanid, void *arg) 623d62bc4baSyz147064 { 624d62bc4baSyz147064 consumer_del_phys_arg_t *del_arg = arg; 625d62bc4baSyz147064 dladm_vlan_attr_t vinfo; 626d62bc4baSyz147064 dladm_status_t status; 627d62bc4baSyz147064 628d62bc4baSyz147064 status = dladm_vlan_info(vlanid, &vinfo, DLADM_OPT_PERSIST); 629d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 630d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 631d62bc4baSyz147064 632d62bc4baSyz147064 if (vinfo.dv_linkid == del_arg->linkid) 633d62bc4baSyz147064 (void) dladm_vlan_delete(vlanid, DLADM_OPT_PERSIST); 634d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 635d62bc4baSyz147064 } 636d62bc4baSyz147064 637d62bc4baSyz147064 static int 638d62bc4baSyz147064 i_dladm_aggr_link_del(datalink_id_t aggrid, void *arg) 639d62bc4baSyz147064 { 640d62bc4baSyz147064 consumer_del_phys_arg_t *del_arg = arg; 641d62bc4baSyz147064 dladm_aggr_grp_attr_t ginfo; 642d62bc4baSyz147064 dladm_status_t status; 643d62bc4baSyz147064 dladm_aggr_port_attr_db_t port[1]; 644d62bc4baSyz147064 int i; 645d62bc4baSyz147064 646d62bc4baSyz147064 status = dladm_aggr_info(aggrid, &ginfo, DLADM_OPT_PERSIST); 647d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 648d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 649d62bc4baSyz147064 650d62bc4baSyz147064 for (i = 0; i < ginfo.lg_nports; i++) 651d62bc4baSyz147064 if (ginfo.lg_ports[i].lp_linkid == del_arg->linkid) 652d62bc4baSyz147064 break; 653d62bc4baSyz147064 654d62bc4baSyz147064 if (i != ginfo.lg_nports) { 655d62bc4baSyz147064 if (ginfo.lg_nports == 1 && i == 0) { 656d62bc4baSyz147064 consumer_del_phys_arg_t aggr_del_arg; 657d62bc4baSyz147064 658d62bc4baSyz147064 /* 659d62bc4baSyz147064 * First delete all the VLANs on this aggregation, then 660d62bc4baSyz147064 * delete the aggregation itself. 661d62bc4baSyz147064 */ 662d62bc4baSyz147064 aggr_del_arg.linkid = aggrid; 663d62bc4baSyz147064 (void) dladm_walk_datalink_id(i_dladm_vlan_link_del, 664d62bc4baSyz147064 &aggr_del_arg, DATALINK_CLASS_VLAN, 665d62bc4baSyz147064 DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 666d62bc4baSyz147064 (void) dladm_aggr_delete(aggrid, DLADM_OPT_PERSIST); 667d62bc4baSyz147064 } else { 668d62bc4baSyz147064 port[0].lp_linkid = del_arg->linkid; 669d62bc4baSyz147064 (void) dladm_aggr_remove(aggrid, 1, port, 670d62bc4baSyz147064 DLADM_OPT_PERSIST); 671d62bc4baSyz147064 } 672d62bc4baSyz147064 } 673d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 674d62bc4baSyz147064 } 675d62bc4baSyz147064 676d62bc4baSyz147064 typedef struct del_phys_arg_s { 677d62bc4baSyz147064 dladm_status_t rval; 678d62bc4baSyz147064 } del_phys_arg_t; 679d62bc4baSyz147064 680d62bc4baSyz147064 static int 681d62bc4baSyz147064 i_dladm_phys_delete(datalink_id_t linkid, void *arg) 682d62bc4baSyz147064 { 683d62bc4baSyz147064 uint32_t flags; 684d62bc4baSyz147064 datalink_class_t class; 685d62bc4baSyz147064 uint32_t media; 686d62bc4baSyz147064 dladm_status_t status = DLADM_STATUS_OK; 687d62bc4baSyz147064 del_phys_arg_t *del_phys_arg = arg; 688d62bc4baSyz147064 consumer_del_phys_arg_t del_arg; 689d62bc4baSyz147064 690d62bc4baSyz147064 if ((status = dladm_datalink_id2info(linkid, &flags, &class, 691d62bc4baSyz147064 &media, NULL, 0)) != DLADM_STATUS_OK) { 692d62bc4baSyz147064 goto done; 693d62bc4baSyz147064 } 694d62bc4baSyz147064 695d62bc4baSyz147064 /* 696d62bc4baSyz147064 * see whether this link is a removed physical link. 697d62bc4baSyz147064 */ 698d62bc4baSyz147064 if ((class != DATALINK_CLASS_PHYS) || !(flags & DLADM_OPT_PERSIST) || 699d62bc4baSyz147064 (flags & DLADM_OPT_ACTIVE)) { 700d62bc4baSyz147064 status = DLADM_STATUS_BADARG; 701d62bc4baSyz147064 goto done; 702d62bc4baSyz147064 } 703d62bc4baSyz147064 704d62bc4baSyz147064 if (media == DL_ETHER) { 705d62bc4baSyz147064 del_arg.linkid = linkid; 706d62bc4baSyz147064 (void) dladm_walk_datalink_id(i_dladm_aggr_link_del, &del_arg, 707d62bc4baSyz147064 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, 708d62bc4baSyz147064 DLADM_OPT_PERSIST); 709d62bc4baSyz147064 (void) dladm_walk_datalink_id(i_dladm_vlan_link_del, &del_arg, 710d62bc4baSyz147064 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, 711d62bc4baSyz147064 DLADM_OPT_PERSIST); 712d62bc4baSyz147064 } 713d62bc4baSyz147064 714d62bc4baSyz147064 (void) dladm_destroy_datalink_id(linkid, DLADM_OPT_PERSIST); 715d62bc4baSyz147064 (void) dladm_remove_conf(linkid); 716d62bc4baSyz147064 717d62bc4baSyz147064 done: 718d62bc4baSyz147064 del_phys_arg->rval = status; 719d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 720d62bc4baSyz147064 } 721d62bc4baSyz147064 722d62bc4baSyz147064 dladm_status_t 723d62bc4baSyz147064 dladm_phys_delete(datalink_id_t linkid) 724d62bc4baSyz147064 { 725d62bc4baSyz147064 del_phys_arg_t arg = {DLADM_STATUS_OK}; 726d62bc4baSyz147064 727d62bc4baSyz147064 if (linkid == DATALINK_ALL_LINKID) { 728d62bc4baSyz147064 (void) dladm_walk_datalink_id(i_dladm_phys_delete, &arg, 729d62bc4baSyz147064 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, 730d62bc4baSyz147064 DLADM_OPT_PERSIST); 731d62bc4baSyz147064 return (DLADM_STATUS_OK); 732d62bc4baSyz147064 } else { 733d62bc4baSyz147064 (void) i_dladm_phys_delete(linkid, &arg); 734d62bc4baSyz147064 return (arg.rval); 735d62bc4baSyz147064 } 736d62bc4baSyz147064 } 737d62bc4baSyz147064 738d62bc4baSyz147064 dladm_status_t 739d62bc4baSyz147064 dladm_phys_info(datalink_id_t linkid, dladm_phys_attr_t *dpap, uint32_t flags) 740d62bc4baSyz147064 { 741d62bc4baSyz147064 dladm_status_t status; 742d62bc4baSyz147064 743d62bc4baSyz147064 assert(flags == DLADM_OPT_ACTIVE || flags == DLADM_OPT_PERSIST); 744d62bc4baSyz147064 745d62bc4baSyz147064 switch (flags) { 746d62bc4baSyz147064 case DLADM_OPT_PERSIST: { 747d62bc4baSyz147064 dladm_conf_t conf; 748d62bc4baSyz147064 749d62bc4baSyz147064 status = dladm_read_conf(linkid, &conf); 750d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 751d62bc4baSyz147064 return (status); 752d62bc4baSyz147064 753d62bc4baSyz147064 status = dladm_get_conf_field(conf, FDEVNAME, dpap->dp_dev, 754d62bc4baSyz147064 MAXLINKNAMELEN); 755d62bc4baSyz147064 dladm_destroy_conf(conf); 756d62bc4baSyz147064 return (status); 757d62bc4baSyz147064 } 758d62bc4baSyz147064 case DLADM_OPT_ACTIVE: { 759d62bc4baSyz147064 dld_ioc_phys_attr_t dip; 760d62bc4baSyz147064 int fd; 761d62bc4baSyz147064 762d62bc4baSyz147064 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 763d62bc4baSyz147064 return (dladm_errno2status(errno)); 764d62bc4baSyz147064 765d62bc4baSyz147064 dip.dip_linkid = linkid; 766d62bc4baSyz147064 if (i_dladm_ioctl(fd, DLDIOC_PHYS_ATTR, &dip, sizeof (dip)) 767d62bc4baSyz147064 < 0) { 768d62bc4baSyz147064 status = dladm_errno2status(errno); 769d62bc4baSyz147064 (void) close(fd); 770d62bc4baSyz147064 return (status); 771d62bc4baSyz147064 } 772d62bc4baSyz147064 (void) close(fd); 773d62bc4baSyz147064 dpap->dp_novanity = dip.dip_novanity; 774d62bc4baSyz147064 (void) strlcpy(dpap->dp_dev, dip.dip_dev, MAXLINKNAMELEN); 775d62bc4baSyz147064 return (DLADM_STATUS_OK); 776d62bc4baSyz147064 } 777d62bc4baSyz147064 default: 778d62bc4baSyz147064 return (DLADM_STATUS_BADARG); 779d62bc4baSyz147064 } 780d62bc4baSyz147064 } 781d62bc4baSyz147064 782d62bc4baSyz147064 typedef struct i_walk_dev_state_s { 783d62bc4baSyz147064 const char *devname; 784d62bc4baSyz147064 datalink_id_t linkid; 785d62bc4baSyz147064 boolean_t found; 786d62bc4baSyz147064 } i_walk_dev_state_t; 787d62bc4baSyz147064 788d62bc4baSyz147064 int 789d62bc4baSyz147064 i_dladm_walk_dev2linkid(datalink_id_t linkid, void *arg) 790d62bc4baSyz147064 { 791d62bc4baSyz147064 dladm_phys_attr_t dpa; 792d62bc4baSyz147064 dladm_status_t status; 793d62bc4baSyz147064 i_walk_dev_state_t *statep = arg; 794d62bc4baSyz147064 795d62bc4baSyz147064 status = dladm_phys_info(linkid, &dpa, DLADM_OPT_PERSIST); 796d62bc4baSyz147064 if ((status == DLADM_STATUS_OK) && 797d62bc4baSyz147064 (strcmp(statep->devname, dpa.dp_dev) == 0)) { 798d62bc4baSyz147064 statep->found = B_TRUE; 799d62bc4baSyz147064 statep->linkid = linkid; 800d62bc4baSyz147064 return (DLADM_WALK_TERMINATE); 801d62bc4baSyz147064 } 802d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 803d62bc4baSyz147064 } 804d62bc4baSyz147064 805d62bc4baSyz147064 /* 806d62bc4baSyz147064 * Get the linkid from the physical device name. 807d62bc4baSyz147064 */ 808d62bc4baSyz147064 dladm_status_t 809d62bc4baSyz147064 dladm_dev2linkid(const char *devname, datalink_id_t *linkidp) 810d62bc4baSyz147064 { 811d62bc4baSyz147064 i_walk_dev_state_t state; 812d62bc4baSyz147064 813d62bc4baSyz147064 state.found = B_FALSE; 814d62bc4baSyz147064 state.devname = devname; 815d62bc4baSyz147064 816d62bc4baSyz147064 (void) dladm_walk_datalink_id(i_dladm_walk_dev2linkid, &state, 817d62bc4baSyz147064 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 818d62bc4baSyz147064 if (state.found == B_TRUE) { 819d62bc4baSyz147064 *linkidp = state.linkid; 820d62bc4baSyz147064 return (DLADM_STATUS_OK); 821d62bc4baSyz147064 } else { 822d62bc4baSyz147064 return (dladm_errno2status(ENOENT)); 823d62bc4baSyz147064 } 824d62bc4baSyz147064 } 825d62bc4baSyz147064 826d62bc4baSyz147064 static int 827d62bc4baSyz147064 parse_devname(const char *devname, char *driver, uint_t *ppa, size_t maxlen) 828d62bc4baSyz147064 { 829d62bc4baSyz147064 char *cp, *tp; 830d62bc4baSyz147064 int len; 831d62bc4baSyz147064 832d62bc4baSyz147064 /* 833d62bc4baSyz147064 * device name length must not be 0, and it must end with digit. 834d62bc4baSyz147064 */ 835d62bc4baSyz147064 if (((len = strlen(devname)) == 0) || !isdigit(devname[len - 1])) 836d62bc4baSyz147064 return (EINVAL); 837d62bc4baSyz147064 838d62bc4baSyz147064 (void) strlcpy(driver, devname, maxlen); 839d62bc4baSyz147064 cp = (char *)&driver[len - 1]; 840d62bc4baSyz147064 841d62bc4baSyz147064 for (tp = cp; isdigit(*tp); tp--) { 842d62bc4baSyz147064 if (tp <= driver) 843d62bc4baSyz147064 return (EINVAL); 844d62bc4baSyz147064 } 845d62bc4baSyz147064 846d62bc4baSyz147064 *ppa = atoi(tp + 1); 847d62bc4baSyz147064 *(tp + 1) = '\0'; 848d62bc4baSyz147064 return (0); 849d62bc4baSyz147064 } 850d62bc4baSyz147064 851d62bc4baSyz147064 dladm_status_t 852d62bc4baSyz147064 dladm_linkid2legacyname(datalink_id_t linkid, char *dev, size_t len) 853d62bc4baSyz147064 { 854d62bc4baSyz147064 char devname[MAXLINKNAMELEN]; 855d62bc4baSyz147064 uint16_t vid = VLAN_ID_NONE; 856d62bc4baSyz147064 datalink_class_t class; 857d62bc4baSyz147064 dladm_status_t status; 858d62bc4baSyz147064 859d62bc4baSyz147064 status = dladm_datalink_id2info(linkid, NULL, &class, NULL, NULL, 0); 860d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 861d62bc4baSyz147064 goto done; 862d62bc4baSyz147064 863d62bc4baSyz147064 /* 864d62bc4baSyz147064 * If this is a VLAN, we must first determine the class and linkid of 865d62bc4baSyz147064 * the link the VLAN has been created over. 866d62bc4baSyz147064 */ 867d62bc4baSyz147064 if (class == DATALINK_CLASS_VLAN) { 868d62bc4baSyz147064 dladm_vlan_attr_t dva; 869d62bc4baSyz147064 870d62bc4baSyz147064 status = dladm_vlan_info(linkid, &dva, DLADM_OPT_ACTIVE); 871d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 872d62bc4baSyz147064 goto done; 873d62bc4baSyz147064 linkid = dva.dv_linkid; 874d62bc4baSyz147064 vid = dva.dv_vid; 875d62bc4baSyz147064 876d62bc4baSyz147064 if ((status = dladm_datalink_id2info(linkid, NULL, &class, NULL, 877d62bc4baSyz147064 NULL, 0)) != DLADM_STATUS_OK) { 878d62bc4baSyz147064 goto done; 879d62bc4baSyz147064 } 880d62bc4baSyz147064 } 881d62bc4baSyz147064 882d62bc4baSyz147064 switch (class) { 883d62bc4baSyz147064 case DATALINK_CLASS_AGGR: { 884d62bc4baSyz147064 dladm_aggr_grp_attr_t dga; 885d62bc4baSyz147064 886d62bc4baSyz147064 status = dladm_aggr_info(linkid, &dga, DLADM_OPT_ACTIVE); 887d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 888d62bc4baSyz147064 goto done; 889d62bc4baSyz147064 890d62bc4baSyz147064 if (dga.lg_key == 0) { 891d62bc4baSyz147064 /* 892d62bc4baSyz147064 * If the key was not specified when the aggregation 893d62bc4baSyz147064 * is created, we cannot guess its /dev node name. 894d62bc4baSyz147064 */ 895d62bc4baSyz147064 status = DLADM_STATUS_BADARG; 896d62bc4baSyz147064 goto done; 897d62bc4baSyz147064 } 898d62bc4baSyz147064 (void) snprintf(devname, MAXLINKNAMELEN, "aggr%d", dga.lg_key); 899d62bc4baSyz147064 break; 900d62bc4baSyz147064 } 901d62bc4baSyz147064 case DATALINK_CLASS_PHYS: { 902d62bc4baSyz147064 dladm_phys_attr_t dpa; 903d62bc4baSyz147064 904d62bc4baSyz147064 status = dladm_phys_info(linkid, &dpa, DLADM_OPT_PERSIST); 905d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 906d62bc4baSyz147064 goto done; 907d62bc4baSyz147064 908d62bc4baSyz147064 (void) strlcpy(devname, dpa.dp_dev, MAXLINKNAMELEN); 909d62bc4baSyz147064 break; 910d62bc4baSyz147064 } 911d62bc4baSyz147064 default: 912d62bc4baSyz147064 status = DLADM_STATUS_BADARG; 913d62bc4baSyz147064 goto done; 914d62bc4baSyz147064 } 915d62bc4baSyz147064 916d62bc4baSyz147064 if (vid != VLAN_ID_NONE) { 917d62bc4baSyz147064 char drv[MAXNAMELEN]; 918d62bc4baSyz147064 uint_t ppa; 919d62bc4baSyz147064 920d62bc4baSyz147064 if (parse_devname(devname, drv, &ppa, MAXNAMELEN) != 0) { 921d62bc4baSyz147064 status = DLADM_STATUS_BADARG; 922d62bc4baSyz147064 goto done; 923d62bc4baSyz147064 } 924d62bc4baSyz147064 if (snprintf(dev, len, "%s%d", drv, vid * 1000 + ppa) >= len) 925d62bc4baSyz147064 status = DLADM_STATUS_TOOSMALL; 926d62bc4baSyz147064 } else { 927d62bc4baSyz147064 if (strlcpy(dev, devname, len) >= len) 928d62bc4baSyz147064 status = DLADM_STATUS_TOOSMALL; 929d62bc4baSyz147064 } 930d62bc4baSyz147064 931d62bc4baSyz147064 done: 932d62bc4baSyz147064 return (status); 933f595a68aSyz147064 } 934e7801d59Ssowmini 935e7801d59Ssowmini dladm_status_t 936e7801d59Ssowmini dladm_get_single_mac_stat(datalink_id_t linkid, const char *name, uint8_t type, 937e7801d59Ssowmini void *val) 938e7801d59Ssowmini { 939e7801d59Ssowmini char module[DLPI_LINKNAME_MAX]; 940e7801d59Ssowmini uint_t instance; 941e7801d59Ssowmini char link[DLPI_LINKNAME_MAX]; 942e7801d59Ssowmini dladm_status_t status; 943e7801d59Ssowmini uint32_t flags, media; 944e7801d59Ssowmini kstat_ctl_t *kcp; 945e7801d59Ssowmini kstat_t *ksp; 946e7801d59Ssowmini dladm_phys_attr_t dpap; 947e7801d59Ssowmini 948e7801d59Ssowmini if ((status = dladm_datalink_id2info(linkid, &flags, NULL, &media, 949e7801d59Ssowmini link, DLPI_LINKNAME_MAX)) != DLADM_STATUS_OK) 950e7801d59Ssowmini return (status); 951e7801d59Ssowmini 952e7801d59Ssowmini if (media != DL_ETHER) 953e7801d59Ssowmini return (DLADM_STATUS_LINKINVAL); 954e7801d59Ssowmini 955e7801d59Ssowmini status = dladm_phys_info(linkid, &dpap, DLADM_OPT_PERSIST); 956e7801d59Ssowmini 957e7801d59Ssowmini if (status != DLADM_STATUS_OK) 958e7801d59Ssowmini return (status); 959e7801d59Ssowmini 960e7801d59Ssowmini status = dladm_parselink(dpap.dp_dev, module, &instance); 961e7801d59Ssowmini 962e7801d59Ssowmini if (status != DLADM_STATUS_OK) 963e7801d59Ssowmini return (status); 964e7801d59Ssowmini 965e7801d59Ssowmini if ((kcp = kstat_open()) == NULL) 966e7801d59Ssowmini return (dladm_errno2status(errno)); 967e7801d59Ssowmini 968e7801d59Ssowmini /* 969e7801d59Ssowmini * The kstat query could fail if the underlying MAC 970e7801d59Ssowmini * driver was already detached. 971e7801d59Ssowmini */ 972e7801d59Ssowmini if ((ksp = kstat_lookup(kcp, module, instance, "mac")) == NULL && 973e7801d59Ssowmini (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL) 974e7801d59Ssowmini goto bail; 975e7801d59Ssowmini 976e7801d59Ssowmini if (kstat_read(kcp, ksp, NULL) == -1) 977e7801d59Ssowmini goto bail; 978e7801d59Ssowmini 979e7801d59Ssowmini if (dladm_kstat_value(ksp, name, type, val) < 0) 980e7801d59Ssowmini goto bail; 981e7801d59Ssowmini 982e7801d59Ssowmini (void) kstat_close(kcp); 983e7801d59Ssowmini return (DLADM_STATUS_OK); 984e7801d59Ssowmini bail: 985e7801d59Ssowmini (void) kstat_close(kcp); 986e7801d59Ssowmini return (dladm_errno2status(errno)); 987e7801d59Ssowmini 988e7801d59Ssowmini } 989e7801d59Ssowmini 990e7801d59Ssowmini int 991e7801d59Ssowmini dladm_kstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf) 992e7801d59Ssowmini { 993e7801d59Ssowmini kstat_named_t *knp; 994e7801d59Ssowmini 995e7801d59Ssowmini if ((knp = kstat_data_lookup(ksp, (char *)name)) == NULL) 996e7801d59Ssowmini return (-1); 997e7801d59Ssowmini 998e7801d59Ssowmini if (knp->data_type != type) 999e7801d59Ssowmini return (-1); 1000e7801d59Ssowmini 1001e7801d59Ssowmini switch (type) { 1002e7801d59Ssowmini case KSTAT_DATA_UINT64: 1003e7801d59Ssowmini *(uint64_t *)buf = knp->value.ui64; 1004e7801d59Ssowmini break; 1005e7801d59Ssowmini case KSTAT_DATA_UINT32: 1006e7801d59Ssowmini *(uint32_t *)buf = knp->value.ui32; 1007e7801d59Ssowmini break; 1008e7801d59Ssowmini default: 1009e7801d59Ssowmini return (-1); 1010e7801d59Ssowmini } 1011e7801d59Ssowmini 1012e7801d59Ssowmini return (0); 1013e7801d59Ssowmini } 1014e7801d59Ssowmini 1015e7801d59Ssowmini dladm_status_t 1016e7801d59Ssowmini dladm_parselink(const char *dev, char *provider, uint_t *ppa) 1017e7801d59Ssowmini { 1018e7801d59Ssowmini ifspec_t ifsp; 1019e7801d59Ssowmini 1020e7801d59Ssowmini if (dev == NULL || !ifparse_ifspec(dev, &ifsp)) 1021e7801d59Ssowmini return (DLADM_STATUS_LINKINVAL); 1022e7801d59Ssowmini 1023e7801d59Ssowmini if (provider != NULL) 1024e7801d59Ssowmini (void) strlcpy(provider, ifsp.ifsp_devnm, DLPI_LINKNAME_MAX); 1025e7801d59Ssowmini 1026e7801d59Ssowmini if (ppa != NULL) 1027e7801d59Ssowmini *ppa = ifsp.ifsp_ppa; 1028e7801d59Ssowmini 1029e7801d59Ssowmini return (DLADM_STATUS_OK); 1030e7801d59Ssowmini } 1031