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