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