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