1f595a68aSyz147064 /* 2f595a68aSyz147064 * CDDL HEADER START 3f595a68aSyz147064 * 4f595a68aSyz147064 * The contents of this file are subject to the terms of the 5f595a68aSyz147064 * Common Development and Distribution License (the "License"). 6f595a68aSyz147064 * You may not use this file except in compliance with the License. 7f595a68aSyz147064 * 8f595a68aSyz147064 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9f595a68aSyz147064 * or http://www.opensolaris.org/os/licensing. 10f595a68aSyz147064 * See the License for the specific language governing permissions 11f595a68aSyz147064 * and limitations under the License. 12f595a68aSyz147064 * 13f595a68aSyz147064 * When distributing Covered Code, include this CDDL HEADER in each 14f595a68aSyz147064 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15f595a68aSyz147064 * If applicable, add the following below this CDDL HEADER, with the 16f595a68aSyz147064 * fields enclosed by brackets "[]" replaced with your own identifying 17f595a68aSyz147064 * information: Portions Copyright [yyyy] [name of copyright owner] 18f595a68aSyz147064 * 19f595a68aSyz147064 * CDDL HEADER END 20f595a68aSyz147064 */ 21f595a68aSyz147064 /* 22*0dc2366fSVenugopal Iyer * Copyright 2010 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> 42*0dc2366fSVenugopal Iyer #include <libdlvnic.h> 43f595a68aSyz147064 #include <libdllink.h> 44d62bc4baSyz147064 #include <libdlmgmt.h> 45f595a68aSyz147064 #include <libdladm_impl.h> 46e7801d59Ssowmini #include <libinetutil.h> 47f595a68aSyz147064 48f595a68aSyz147064 /* 49f595a68aSyz147064 * Return the attributes of the specified datalink from the DLD driver. 50f595a68aSyz147064 */ 51d62bc4baSyz147064 static dladm_status_t 524ac67f02SAnurag S. Maskey i_dladm_info(dladm_handle_t handle, const datalink_id_t linkid, 534ac67f02SAnurag S. Maskey dladm_attr_t *dap) 54f595a68aSyz147064 { 55f595a68aSyz147064 dld_ioc_attr_t dia; 56f595a68aSyz147064 57d62bc4baSyz147064 dia.dia_linkid = linkid; 58f595a68aSyz147064 594ac67f02SAnurag S. Maskey if (ioctl(dladm_dld_fd(handle), DLDIOC_ATTR, &dia) < 0) 60d62bc4baSyz147064 return (dladm_errno2status(errno)); 61f595a68aSyz147064 62f595a68aSyz147064 dap->da_max_sdu = dia.dia_max_sdu; 63f595a68aSyz147064 64d62bc4baSyz147064 return (DLADM_STATUS_OK); 65f595a68aSyz147064 } 66f595a68aSyz147064 67da14cebeSEric Cheng static dladm_status_t 684ac67f02SAnurag S. Maskey dladm_usagelog(dladm_handle_t handle, dladm_logtype_t type, 694ac67f02SAnurag S. Maskey dld_ioc_usagelog_t *log_info) 70da14cebeSEric Cheng { 71da14cebeSEric Cheng if (type == DLADM_LOGTYPE_FLOW) 72da14cebeSEric Cheng log_info->ul_type = MAC_LOGTYPE_FLOW; 73da14cebeSEric Cheng else 74da14cebeSEric Cheng log_info->ul_type = MAC_LOGTYPE_LINK; 75da14cebeSEric Cheng 764ac67f02SAnurag S. Maskey if (ioctl(dladm_dld_fd(handle), DLDIOC_USAGELOG, log_info) < 0) 77da14cebeSEric Cheng return (DLADM_STATUS_IOERR); 784ac67f02SAnurag S. Maskey 79da14cebeSEric Cheng return (DLADM_STATUS_OK); 80da14cebeSEric Cheng } 81da14cebeSEric Cheng 82da14cebeSEric Cheng dladm_status_t 834ac67f02SAnurag S. Maskey dladm_start_usagelog(dladm_handle_t handle, dladm_logtype_t type, 844ac67f02SAnurag S. Maskey uint_t interval) 85da14cebeSEric Cheng { 86da14cebeSEric Cheng dld_ioc_usagelog_t log_info; 87da14cebeSEric Cheng 88da14cebeSEric Cheng log_info.ul_onoff = B_TRUE; 89da14cebeSEric Cheng log_info.ul_interval = interval; 90da14cebeSEric Cheng 914ac67f02SAnurag S. Maskey return (dladm_usagelog(handle, type, &log_info)); 92da14cebeSEric Cheng } 93da14cebeSEric Cheng 94da14cebeSEric Cheng dladm_status_t 954ac67f02SAnurag S. Maskey dladm_stop_usagelog(dladm_handle_t handle, dladm_logtype_t type) 96da14cebeSEric Cheng { 97da14cebeSEric Cheng dld_ioc_usagelog_t log_info; 98da14cebeSEric Cheng 99da14cebeSEric Cheng log_info.ul_onoff = B_FALSE; 100da14cebeSEric Cheng log_info.ul_interval = 0; 101da14cebeSEric Cheng 1024ac67f02SAnurag S. Maskey return (dladm_usagelog(handle, type, &log_info)); 103da14cebeSEric Cheng } 104da14cebeSEric Cheng 105d62bc4baSyz147064 struct i_dladm_walk_arg { 106d62bc4baSyz147064 dladm_walkcb_t *fn; 107d62bc4baSyz147064 void *arg; 108d62bc4baSyz147064 }; 109f595a68aSyz147064 110f595a68aSyz147064 static int 1114ac67f02SAnurag S. Maskey i_dladm_walk(dladm_handle_t handle, datalink_id_t linkid, void *arg) 112f595a68aSyz147064 { 113d62bc4baSyz147064 struct i_dladm_walk_arg *walk_arg = arg; 114d62bc4baSyz147064 char link[MAXLINKNAMELEN]; 115f595a68aSyz147064 1164ac67f02SAnurag S. Maskey if (dladm_datalink_id2info(handle, linkid, NULL, NULL, NULL, link, 117d62bc4baSyz147064 sizeof (link)) == DLADM_STATUS_OK) { 118d62bc4baSyz147064 return (walk_arg->fn(link, walk_arg->arg)); 119f595a68aSyz147064 } 120d62bc4baSyz147064 121d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 122f595a68aSyz147064 } 123f595a68aSyz147064 124f595a68aSyz147064 /* 125d62bc4baSyz147064 * Walk all datalinks. 126f595a68aSyz147064 */ 127d62bc4baSyz147064 dladm_status_t 1284ac67f02SAnurag S. Maskey dladm_walk(dladm_walkcb_t *fn, dladm_handle_t handle, void *arg, 1294ac67f02SAnurag S. Maskey datalink_class_t class, datalink_media_t dmedia, uint32_t flags) 130f595a68aSyz147064 { 131d62bc4baSyz147064 struct i_dladm_walk_arg walk_arg; 132f595a68aSyz147064 133d62bc4baSyz147064 walk_arg.fn = fn; 134d62bc4baSyz147064 walk_arg.arg = arg; 1354ac67f02SAnurag S. Maskey return (dladm_walk_datalink_id(i_dladm_walk, handle, &walk_arg, 136d62bc4baSyz147064 class, dmedia, flags)); 137f595a68aSyz147064 } 138f595a68aSyz147064 139da14cebeSEric Cheng #define MAXGRPPERLINK 64 140da14cebeSEric Cheng 141da14cebeSEric Cheng int 1424ac67f02SAnurag S. Maskey dladm_walk_hwgrp(dladm_handle_t handle, datalink_id_t linkid, void *arg, 143da14cebeSEric Cheng boolean_t (*fn)(void *, dladm_hwgrp_attr_t *)) 144da14cebeSEric Cheng { 1454ac67f02SAnurag S. Maskey int bufsize, ret; 146da14cebeSEric Cheng int nhwgrp = MAXGRPPERLINK; 147da14cebeSEric Cheng dld_ioc_hwgrpget_t *iomp = NULL; 148da14cebeSEric Cheng 149da14cebeSEric Cheng bufsize = sizeof (dld_ioc_hwgrpget_t) + 150da14cebeSEric Cheng nhwgrp * sizeof (dld_hwgrpinfo_t); 151da14cebeSEric Cheng 152da14cebeSEric Cheng if ((iomp = (dld_ioc_hwgrpget_t *)calloc(1, bufsize)) == NULL) 153da14cebeSEric Cheng return (-1); 154da14cebeSEric Cheng 155da14cebeSEric Cheng iomp->dih_size = nhwgrp * sizeof (dld_hwgrpinfo_t); 156da14cebeSEric Cheng iomp->dih_linkid = linkid; 157da14cebeSEric Cheng 1584ac67f02SAnurag S. Maskey ret = ioctl(dladm_dld_fd(handle), DLDIOC_GETHWGRP, iomp); 159da14cebeSEric Cheng if (ret == 0) { 160da14cebeSEric Cheng int i; 161*0dc2366fSVenugopal Iyer int j; 162da14cebeSEric Cheng dld_hwgrpinfo_t *dhip; 163da14cebeSEric Cheng dladm_hwgrp_attr_t attr; 164da14cebeSEric Cheng 165da14cebeSEric Cheng dhip = (dld_hwgrpinfo_t *)(iomp + 1); 166da14cebeSEric Cheng for (i = 0; i < iomp->dih_n_groups; i++) { 167da14cebeSEric Cheng bzero(&attr, sizeof (attr)); 168da14cebeSEric Cheng 169da14cebeSEric Cheng (void) strlcpy(attr.hg_link_name, 170da14cebeSEric Cheng dhip->dhi_link_name, sizeof (attr.hg_link_name)); 171da14cebeSEric Cheng attr.hg_grp_num = dhip->dhi_grp_num; 172da14cebeSEric Cheng attr.hg_grp_type = dhip->dhi_grp_type; 173da14cebeSEric Cheng attr.hg_n_rings = dhip->dhi_n_rings; 174*0dc2366fSVenugopal Iyer for (j = 0; j < dhip->dhi_n_rings; j++) 175*0dc2366fSVenugopal Iyer attr.hg_rings[j] = dhip->dhi_rings[j]; 176*0dc2366fSVenugopal Iyer dladm_sort_index_list(attr.hg_rings, attr.hg_n_rings); 177da14cebeSEric Cheng attr.hg_n_clnts = dhip->dhi_n_clnts; 178da14cebeSEric Cheng (void) strlcpy(attr.hg_client_names, 179da14cebeSEric Cheng dhip->dhi_clnts, sizeof (attr.hg_client_names)); 180da14cebeSEric Cheng 181da14cebeSEric Cheng if (!(*fn)(arg, &attr)) 182da14cebeSEric Cheng break; 183da14cebeSEric Cheng dhip++; 184da14cebeSEric Cheng } 185da14cebeSEric Cheng } 186da14cebeSEric Cheng free(iomp); 187da14cebeSEric Cheng return (ret); 188da14cebeSEric Cheng } 189da14cebeSEric Cheng 190da14cebeSEric Cheng /* 191da14cebeSEric Cheng * Invoke the specified callback for each MAC address entry defined on 192da14cebeSEric Cheng * the specified device. 193da14cebeSEric Cheng */ 194da14cebeSEric Cheng int 1954ac67f02SAnurag S. Maskey dladm_walk_macaddr(dladm_handle_t handle, datalink_id_t linkid, void *arg, 196da14cebeSEric Cheng boolean_t (*fn)(void *, dladm_macaddr_attr_t *)) 197da14cebeSEric Cheng { 1984ac67f02SAnurag S. Maskey int bufsize, ret; 199da14cebeSEric Cheng int nmacaddr = 1024; 200da14cebeSEric Cheng dld_ioc_macaddrget_t *iomp = NULL; 201da14cebeSEric Cheng 202da14cebeSEric Cheng bufsize = sizeof (dld_ioc_macaddrget_t) + 203da14cebeSEric Cheng nmacaddr * sizeof (dld_macaddrinfo_t); 204da14cebeSEric Cheng 205da14cebeSEric Cheng if ((iomp = (dld_ioc_macaddrget_t *)calloc(1, bufsize)) == NULL) 206da14cebeSEric Cheng return (-1); 207da14cebeSEric Cheng 208da14cebeSEric Cheng iomp->dig_size = nmacaddr * sizeof (dld_macaddrinfo_t); 209da14cebeSEric Cheng iomp->dig_linkid = linkid; 210da14cebeSEric Cheng 2114ac67f02SAnurag S. Maskey ret = ioctl(dladm_dld_fd(handle), DLDIOC_MACADDRGET, iomp); 212da14cebeSEric Cheng if (ret == 0) { 213da14cebeSEric Cheng int i; 214da14cebeSEric Cheng dld_macaddrinfo_t *dmip; 215da14cebeSEric Cheng dladm_macaddr_attr_t attr; 216da14cebeSEric Cheng 217da14cebeSEric Cheng dmip = (dld_macaddrinfo_t *)(iomp + 1); 218da14cebeSEric Cheng for (i = 0; i < iomp->dig_count; i++) { 219da14cebeSEric Cheng bzero(&attr, sizeof (attr)); 220da14cebeSEric Cheng 221da14cebeSEric Cheng attr.ma_slot = dmip->dmi_slot; 222da14cebeSEric Cheng attr.ma_flags = 0; 223da14cebeSEric Cheng if (dmip->dmi_flags & DLDIOCMACADDR_USED) 224da14cebeSEric Cheng attr.ma_flags |= DLADM_MACADDR_USED; 225da14cebeSEric Cheng bcopy(dmip->dmi_addr, attr.ma_addr, 226da14cebeSEric Cheng dmip->dmi_addrlen); 227da14cebeSEric Cheng attr.ma_addrlen = dmip->dmi_addrlen; 228da14cebeSEric Cheng (void) strlcpy(attr.ma_client_name, 229da14cebeSEric Cheng dmip->dmi_client_name, MAXNAMELEN); 230da14cebeSEric Cheng attr.ma_client_linkid = dmip->dma_client_linkid; 231da14cebeSEric Cheng 232da14cebeSEric Cheng if (!(*fn)(arg, &attr)) 233da14cebeSEric Cheng break; 234da14cebeSEric Cheng dmip++; 235da14cebeSEric Cheng } 236da14cebeSEric Cheng } 237da14cebeSEric Cheng free(iomp); 238da14cebeSEric Cheng return (ret); 239da14cebeSEric Cheng } 240da14cebeSEric Cheng 241f595a68aSyz147064 /* 242d62bc4baSyz147064 * These routines are used by administration tools such as dladm(1M) to 243f595a68aSyz147064 * iterate through the list of MAC interfaces 244f595a68aSyz147064 */ 245f595a68aSyz147064 246f595a68aSyz147064 typedef struct dladm_mac_dev { 247f595a68aSyz147064 char dm_name[MAXNAMELEN]; 248f595a68aSyz147064 struct dladm_mac_dev *dm_next; 249f595a68aSyz147064 } dladm_mac_dev_t; 250f595a68aSyz147064 251f595a68aSyz147064 typedef struct macadm_walk { 252f595a68aSyz147064 dladm_mac_dev_t *dmd_dev_list; 253f595a68aSyz147064 } dladm_mac_walk_t; 254f595a68aSyz147064 255f595a68aSyz147064 /* 256f595a68aSyz147064 * Local callback invoked for each DDI_NT_NET node. 257f595a68aSyz147064 */ 258f595a68aSyz147064 /* ARGSUSED */ 259f595a68aSyz147064 static int 260f595a68aSyz147064 i_dladm_mac_walk(di_node_t node, di_minor_t minor, void *arg) 261f595a68aSyz147064 { 262f595a68aSyz147064 dladm_mac_walk_t *dmwp = arg; 263f595a68aSyz147064 dladm_mac_dev_t *dmdp = dmwp->dmd_dev_list; 264f595a68aSyz147064 dladm_mac_dev_t **last_dmdp = &dmwp->dmd_dev_list; 265f595a68aSyz147064 char mac[MAXNAMELEN]; 266f595a68aSyz147064 267f595a68aSyz147064 (void) snprintf(mac, MAXNAMELEN, "%s%d", 268f595a68aSyz147064 di_driver_name(node), di_instance(node)); 269f595a68aSyz147064 270f595a68aSyz147064 /* 271f595a68aSyz147064 * Skip aggregations. 272f595a68aSyz147064 */ 273f595a68aSyz147064 if (strcmp("aggr", di_driver_name(node)) == 0) 274f595a68aSyz147064 return (DI_WALK_CONTINUE); 275f595a68aSyz147064 276d62bc4baSyz147064 /* 277d62bc4baSyz147064 * Skip softmacs. 278d62bc4baSyz147064 */ 279d62bc4baSyz147064 if (strcmp("softmac", di_driver_name(node)) == 0) 280d62bc4baSyz147064 return (DI_WALK_CONTINUE); 281d62bc4baSyz147064 282f595a68aSyz147064 while (dmdp) { 283f595a68aSyz147064 /* 284f595a68aSyz147064 * Skip duplicates. 285f595a68aSyz147064 */ 286f595a68aSyz147064 if (strcmp(dmdp->dm_name, mac) == 0) 287f595a68aSyz147064 return (DI_WALK_CONTINUE); 288f595a68aSyz147064 289f595a68aSyz147064 last_dmdp = &dmdp->dm_next; 290f595a68aSyz147064 dmdp = dmdp->dm_next; 291f595a68aSyz147064 } 292f595a68aSyz147064 293f595a68aSyz147064 if ((dmdp = malloc(sizeof (*dmdp))) == NULL) 294f595a68aSyz147064 return (DI_WALK_CONTINUE); 295f595a68aSyz147064 296f595a68aSyz147064 (void) strlcpy(dmdp->dm_name, mac, MAXNAMELEN); 297f595a68aSyz147064 dmdp->dm_next = NULL; 298f595a68aSyz147064 *last_dmdp = dmdp; 299f595a68aSyz147064 300f595a68aSyz147064 return (DI_WALK_CONTINUE); 301f595a68aSyz147064 } 302f595a68aSyz147064 303f595a68aSyz147064 /* 304d62bc4baSyz147064 * Invoke the specified callback for each DDI_NT_NET node. 305f595a68aSyz147064 */ 306d62bc4baSyz147064 dladm_status_t 307d62bc4baSyz147064 dladm_mac_walk(int (*fn)(const char *, void *arg), void *arg) 308f595a68aSyz147064 { 309f595a68aSyz147064 di_node_t root; 310f595a68aSyz147064 dladm_mac_walk_t dmw; 311f595a68aSyz147064 dladm_mac_dev_t *dmdp, *next; 312d62bc4baSyz147064 boolean_t done = B_FALSE; 313f595a68aSyz147064 314f595a68aSyz147064 if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) 315d62bc4baSyz147064 return (dladm_errno2status(errno)); 316f595a68aSyz147064 317f595a68aSyz147064 dmw.dmd_dev_list = NULL; 318f595a68aSyz147064 319f595a68aSyz147064 (void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, &dmw, 320f595a68aSyz147064 i_dladm_mac_walk); 321f595a68aSyz147064 322f595a68aSyz147064 di_fini(root); 323f595a68aSyz147064 324f595a68aSyz147064 dmdp = dmw.dmd_dev_list; 325f595a68aSyz147064 for (dmdp = dmw.dmd_dev_list; dmdp != NULL; dmdp = next) { 326f595a68aSyz147064 next = dmdp->dm_next; 327d62bc4baSyz147064 if (!done && 328d62bc4baSyz147064 ((*fn)(dmdp->dm_name, arg) == DLADM_WALK_TERMINATE)) { 329d62bc4baSyz147064 done = B_TRUE; 330d62bc4baSyz147064 } 331f595a68aSyz147064 free(dmdp); 332f595a68aSyz147064 } 333f595a68aSyz147064 334d62bc4baSyz147064 return (DLADM_STATUS_OK); 335f595a68aSyz147064 } 336f595a68aSyz147064 337f595a68aSyz147064 /* 338d62bc4baSyz147064 * Get the current attributes of the specified datalink. 339f595a68aSyz147064 */ 340d62bc4baSyz147064 dladm_status_t 3414ac67f02SAnurag S. Maskey dladm_info(dladm_handle_t handle, datalink_id_t linkid, dladm_attr_t *dap) 342f595a68aSyz147064 { 3434ac67f02SAnurag S. Maskey return (i_dladm_info(handle, linkid, dap)); 344f595a68aSyz147064 } 345f595a68aSyz147064 346f595a68aSyz147064 const char * 347f595a68aSyz147064 dladm_linkstate2str(link_state_t state, char *buf) 348f595a68aSyz147064 { 349f595a68aSyz147064 const char *s; 350f595a68aSyz147064 351f595a68aSyz147064 switch (state) { 352f595a68aSyz147064 case LINK_STATE_UP: 353f595a68aSyz147064 s = "up"; 354f595a68aSyz147064 break; 355f595a68aSyz147064 case LINK_STATE_DOWN: 356f595a68aSyz147064 s = "down"; 357f595a68aSyz147064 break; 358f595a68aSyz147064 default: 359f595a68aSyz147064 s = "unknown"; 360f595a68aSyz147064 break; 361f595a68aSyz147064 } 362f595a68aSyz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 363f595a68aSyz147064 return (buf); 364f595a68aSyz147064 } 365f595a68aSyz147064 366f595a68aSyz147064 const char * 367f595a68aSyz147064 dladm_linkduplex2str(link_duplex_t duplex, char *buf) 368f595a68aSyz147064 { 369f595a68aSyz147064 const char *s; 370f595a68aSyz147064 371f595a68aSyz147064 switch (duplex) { 372f595a68aSyz147064 case LINK_DUPLEX_FULL: 373f595a68aSyz147064 s = "full"; 374f595a68aSyz147064 break; 375f595a68aSyz147064 case LINK_DUPLEX_HALF: 376f595a68aSyz147064 s = "half"; 377f595a68aSyz147064 break; 378f595a68aSyz147064 default: 379f595a68aSyz147064 s = "unknown"; 380f595a68aSyz147064 break; 381f595a68aSyz147064 } 382f595a68aSyz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 383f595a68aSyz147064 return (buf); 384f595a68aSyz147064 } 385f595a68aSyz147064 386f595a68aSyz147064 /* 387d62bc4baSyz147064 * Case 1: rename an existing link1 to a link2 that does not exist. 388d62bc4baSyz147064 * Result: <linkid1, link2> 389d62bc4baSyz147064 */ 390d62bc4baSyz147064 static dladm_status_t 3914ac67f02SAnurag S. Maskey i_dladm_rename_link_c1(dladm_handle_t handle, datalink_id_t linkid1, 3924ac67f02SAnurag S. Maskey const char *link1, const char *link2, uint32_t flags) 393d62bc4baSyz147064 { 394d62bc4baSyz147064 dld_ioc_rename_t dir; 395d62bc4baSyz147064 dladm_status_t status = DLADM_STATUS_OK; 396d62bc4baSyz147064 397d62bc4baSyz147064 /* 398d62bc4baSyz147064 * Link is currently available. Check to see whether anything is 399d62bc4baSyz147064 * holding this link to prevent a rename operation. 400d62bc4baSyz147064 */ 401d62bc4baSyz147064 if (flags & DLADM_OPT_ACTIVE) { 402d62bc4baSyz147064 dir.dir_linkid1 = linkid1; 403d62bc4baSyz147064 dir.dir_linkid2 = DATALINK_INVALID_LINKID; 404d62bc4baSyz147064 (void) strlcpy(dir.dir_link, link2, MAXLINKNAMELEN); 405d62bc4baSyz147064 4064ac67f02SAnurag S. Maskey if (ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir) < 0) { 407d62bc4baSyz147064 status = dladm_errno2status(errno); 408d62bc4baSyz147064 return (status); 409d62bc4baSyz147064 } 410d62bc4baSyz147064 } 411d62bc4baSyz147064 4124ac67f02SAnurag S. Maskey status = dladm_remap_datalink_id(handle, linkid1, link2); 4132b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK && (flags & DLADM_OPT_ACTIVE)) { 414d62bc4baSyz147064 (void) strlcpy(dir.dir_link, link1, MAXLINKNAMELEN); 4154ac67f02SAnurag S. Maskey (void) ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir); 416d62bc4baSyz147064 } 417d62bc4baSyz147064 return (status); 418d62bc4baSyz147064 } 419d62bc4baSyz147064 420d62bc4baSyz147064 typedef struct link_hold_arg_s { 421d62bc4baSyz147064 datalink_id_t linkid; 422d62bc4baSyz147064 datalink_id_t holder; 423d62bc4baSyz147064 uint32_t flags; 424d62bc4baSyz147064 } link_hold_arg_t; 425d62bc4baSyz147064 426d62bc4baSyz147064 static int 4274ac67f02SAnurag S. Maskey i_dladm_aggr_link_hold(dladm_handle_t handle, datalink_id_t aggrid, void *arg) 428d62bc4baSyz147064 { 429d62bc4baSyz147064 link_hold_arg_t *hold_arg = arg; 430d62bc4baSyz147064 dladm_aggr_grp_attr_t ginfo; 431d62bc4baSyz147064 dladm_status_t status; 432d62bc4baSyz147064 int i; 433d62bc4baSyz147064 4344ac67f02SAnurag S. Maskey status = dladm_aggr_info(handle, aggrid, &ginfo, hold_arg->flags); 435d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 436d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 437d62bc4baSyz147064 438d62bc4baSyz147064 for (i = 0; i < ginfo.lg_nports; i++) { 439d62bc4baSyz147064 if (ginfo.lg_ports[i].lp_linkid == hold_arg->linkid) { 440d62bc4baSyz147064 hold_arg->holder = aggrid; 441d62bc4baSyz147064 return (DLADM_WALK_TERMINATE); 442d62bc4baSyz147064 } 443d62bc4baSyz147064 } 444d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 445d62bc4baSyz147064 } 446d62bc4baSyz147064 447d62bc4baSyz147064 static int 4484ac67f02SAnurag S. Maskey i_dladm_vlan_link_hold(dladm_handle_t handle, datalink_id_t vlanid, void *arg) 449d62bc4baSyz147064 { 450d62bc4baSyz147064 link_hold_arg_t *hold_arg = arg; 451d62bc4baSyz147064 dladm_vlan_attr_t vinfo; 452d62bc4baSyz147064 dladm_status_t status; 453d62bc4baSyz147064 4544ac67f02SAnurag S. Maskey status = dladm_vlan_info(handle, vlanid, &vinfo, hold_arg->flags); 455d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 456d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 457d62bc4baSyz147064 458d62bc4baSyz147064 if (vinfo.dv_linkid == hold_arg->linkid) { 459d62bc4baSyz147064 hold_arg->holder = vlanid; 460d62bc4baSyz147064 return (DLADM_WALK_TERMINATE); 461d62bc4baSyz147064 } 462d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 463d62bc4baSyz147064 } 464d62bc4baSyz147064 465d62bc4baSyz147064 /* 466d62bc4baSyz147064 * Case 2: rename an available physical link link1 to a REMOVED physical link 467d62bc4baSyz147064 * link2. As a result, link1 directly inherits all datalinks configured 468d62bc4baSyz147064 * over link2 (linkid2). 469d62bc4baSyz147064 * Result: <linkid2, link2, link1_phymaj, link1_phyinst, link1_devname, 470d62bc4baSyz147064 * link2_other_attr> 471d62bc4baSyz147064 */ 472d62bc4baSyz147064 static dladm_status_t 4734ac67f02SAnurag S. Maskey i_dladm_rename_link_c2(dladm_handle_t handle, datalink_id_t linkid1, 4744ac67f02SAnurag S. Maskey datalink_id_t linkid2) 475d62bc4baSyz147064 { 476d62bc4baSyz147064 rcm_handle_t *rcm_hdl = NULL; 477d62bc4baSyz147064 nvlist_t *nvl = NULL; 478d62bc4baSyz147064 link_hold_arg_t arg; 479d62bc4baSyz147064 dld_ioc_rename_t dir; 480d62bc4baSyz147064 dladm_conf_t conf1, conf2; 481d62bc4baSyz147064 char devname[MAXLINKNAMELEN]; 482d62bc4baSyz147064 uint64_t phymaj, phyinst; 483d62bc4baSyz147064 dladm_status_t status = DLADM_STATUS_OK; 484d62bc4baSyz147064 485d62bc4baSyz147064 /* 486d62bc4baSyz147064 * First check if linkid1 is associated with any persistent 487d62bc4baSyz147064 * aggregations or VLANs. If yes, return BUSY. 488d62bc4baSyz147064 */ 489d62bc4baSyz147064 arg.linkid = linkid1; 490d62bc4baSyz147064 arg.holder = DATALINK_INVALID_LINKID; 491d62bc4baSyz147064 arg.flags = DLADM_OPT_PERSIST; 4924ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(i_dladm_aggr_link_hold, handle, &arg, 493d62bc4baSyz147064 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 494d62bc4baSyz147064 if (arg.holder != DATALINK_INVALID_LINKID) 495d62bc4baSyz147064 return (DLADM_STATUS_LINKBUSY); 496d62bc4baSyz147064 497d62bc4baSyz147064 arg.flags = DLADM_OPT_PERSIST; 4984ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(i_dladm_vlan_link_hold, handle, &arg, 499d62bc4baSyz147064 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 500d62bc4baSyz147064 if (arg.holder != DATALINK_INVALID_LINKID) 501d62bc4baSyz147064 return (DLADM_STATUS_LINKBUSY); 502d62bc4baSyz147064 503d62bc4baSyz147064 /* 504d62bc4baSyz147064 * Send DLDIOC_RENAME to request to rename link1's linkid to 505d62bc4baSyz147064 * be linkid2. This will check whether link1 is used by any 506d62bc4baSyz147064 * aggregations or VLANs, or is held by any application. If yes, 507d62bc4baSyz147064 * return failure. 508d62bc4baSyz147064 */ 509d62bc4baSyz147064 dir.dir_linkid1 = linkid1; 510d62bc4baSyz147064 dir.dir_linkid2 = linkid2; 5114ac67f02SAnurag S. Maskey if (ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir) < 0) 512d62bc4baSyz147064 status = dladm_errno2status(errno); 513d62bc4baSyz147064 514d62bc4baSyz147064 if (status != DLADM_STATUS_OK) { 515d62bc4baSyz147064 return (status); 516d62bc4baSyz147064 } 517d62bc4baSyz147064 518d62bc4baSyz147064 /* 519d62bc4baSyz147064 * Now change the phymaj, phyinst and devname associated with linkid1 520d62bc4baSyz147064 * to be associated with linkid2. Before doing that, the old active 521d62bc4baSyz147064 * linkprop of linkid1 should be deleted. 522d62bc4baSyz147064 */ 5234ac67f02SAnurag S. Maskey (void) dladm_set_linkprop(handle, linkid1, NULL, NULL, 0, 5244ac67f02SAnurag S. Maskey DLADM_OPT_ACTIVE); 525d62bc4baSyz147064 5264ac67f02SAnurag S. Maskey if (((status = dladm_read_conf(handle, linkid1, &conf1)) != 5274ac67f02SAnurag S. Maskey DLADM_STATUS_OK) || 5284ac67f02SAnurag S. Maskey ((status = dladm_get_conf_field(handle, conf1, FDEVNAME, devname, 529d62bc4baSyz147064 MAXLINKNAMELEN)) != DLADM_STATUS_OK) || 5304ac67f02SAnurag S. Maskey ((status = dladm_get_conf_field(handle, conf1, FPHYMAJ, &phymaj, 531d62bc4baSyz147064 sizeof (uint64_t))) != DLADM_STATUS_OK) || 5324ac67f02SAnurag S. Maskey ((status = dladm_get_conf_field(handle, conf1, FPHYINST, &phyinst, 533d62bc4baSyz147064 sizeof (uint64_t))) != DLADM_STATUS_OK) || 5344ac67f02SAnurag S. Maskey ((status = dladm_read_conf(handle, linkid2, &conf2)) != 5354ac67f02SAnurag S. Maskey DLADM_STATUS_OK)) { 536d62bc4baSyz147064 dir.dir_linkid1 = linkid2; 537d62bc4baSyz147064 dir.dir_linkid2 = linkid1; 5384ac67f02SAnurag S. Maskey (void) dladm_init_linkprop(handle, linkid1, B_FALSE); 5394ac67f02SAnurag S. Maskey (void) ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir); 540d62bc4baSyz147064 return (status); 541d62bc4baSyz147064 } 542d62bc4baSyz147064 5434ac67f02SAnurag S. Maskey dladm_destroy_conf(handle, conf1); 5444ac67f02SAnurag S. Maskey (void) dladm_set_conf_field(handle, conf2, FDEVNAME, DLADM_TYPE_STR, 5454ac67f02SAnurag S. Maskey devname); 5464ac67f02SAnurag S. Maskey (void) dladm_set_conf_field(handle, conf2, FPHYMAJ, DLADM_TYPE_UINT64, 5474ac67f02SAnurag S. Maskey &phymaj); 5484ac67f02SAnurag S. Maskey (void) dladm_set_conf_field(handle, conf2, FPHYINST, 549d62bc4baSyz147064 DLADM_TYPE_UINT64, &phyinst); 5504ac67f02SAnurag S. Maskey (void) dladm_write_conf(handle, conf2); 5514ac67f02SAnurag S. Maskey dladm_destroy_conf(handle, conf2); 552d62bc4baSyz147064 553d62bc4baSyz147064 /* 554d62bc4baSyz147064 * Delete link1 and mark link2 up. 555d62bc4baSyz147064 */ 5562b24ab6bSSebastien Roy (void) dladm_remove_conf(handle, linkid1); 5574ac67f02SAnurag S. Maskey (void) dladm_destroy_datalink_id(handle, linkid1, DLADM_OPT_ACTIVE | 558d62bc4baSyz147064 DLADM_OPT_PERSIST); 5594ac67f02SAnurag S. Maskey (void) dladm_up_datalink_id(handle, linkid2); 560d62bc4baSyz147064 561d62bc4baSyz147064 /* 562d62bc4baSyz147064 * Now generate the RCM_RESOURCE_LINK_NEW sysevent which can be 563d62bc4baSyz147064 * consumed by the RCM framework to restore all the datalink and 564d62bc4baSyz147064 * IP configuration. 565d62bc4baSyz147064 */ 566d62bc4baSyz147064 status = DLADM_STATUS_FAILED; 567d62bc4baSyz147064 if ((nvlist_alloc(&nvl, 0, 0) != 0) || 568d62bc4baSyz147064 (nvlist_add_uint64(nvl, RCM_NV_LINKID, linkid2) != 0)) { 569d62bc4baSyz147064 goto done; 570d62bc4baSyz147064 } 571d62bc4baSyz147064 572d62bc4baSyz147064 if (rcm_alloc_handle(NULL, 0, NULL, &rcm_hdl) != RCM_SUCCESS) 573d62bc4baSyz147064 goto done; 574d62bc4baSyz147064 575d62bc4baSyz147064 if (rcm_notify_event(rcm_hdl, RCM_RESOURCE_LINK_NEW, 0, nvl, NULL) == 576d62bc4baSyz147064 RCM_SUCCESS) { 577d62bc4baSyz147064 status = DLADM_STATUS_OK; 578d62bc4baSyz147064 } 579d62bc4baSyz147064 580d62bc4baSyz147064 done: 581d62bc4baSyz147064 if (rcm_hdl != NULL) 582d62bc4baSyz147064 (void) rcm_free_handle(rcm_hdl); 583d62bc4baSyz147064 if (nvl != NULL) 584d62bc4baSyz147064 nvlist_free(nvl); 585d62bc4baSyz147064 return (status); 586d62bc4baSyz147064 } 587d62bc4baSyz147064 588d62bc4baSyz147064 /* 589d62bc4baSyz147064 * case 3: rename a non-existent link to a REMOVED physical link. 590d62bc4baSyz147064 * Set the removed physical link's device name to link1, so that 591d62bc4baSyz147064 * when link1 attaches, it inherits all the link configuration of 592d62bc4baSyz147064 * the removed physical link. 593d62bc4baSyz147064 */ 594d62bc4baSyz147064 static dladm_status_t 5954ac67f02SAnurag S. Maskey i_dladm_rename_link_c3(dladm_handle_t handle, const char *link1, 5964ac67f02SAnurag S. Maskey datalink_id_t linkid2) 597d62bc4baSyz147064 { 598d62bc4baSyz147064 dladm_conf_t conf; 599d62bc4baSyz147064 dladm_status_t status; 600d62bc4baSyz147064 601d62bc4baSyz147064 if (!dladm_valid_linkname(link1)) 602d62bc4baSyz147064 return (DLADM_STATUS_LINKINVAL); 603d62bc4baSyz147064 6044ac67f02SAnurag S. Maskey status = dladm_read_conf(handle, linkid2, &conf); 605d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 606d62bc4baSyz147064 goto done; 607d62bc4baSyz147064 6084ac67f02SAnurag S. Maskey if ((status = dladm_set_conf_field(handle, conf, FDEVNAME, 6094ac67f02SAnurag S. Maskey DLADM_TYPE_STR, link1)) == DLADM_STATUS_OK) { 6104ac67f02SAnurag S. Maskey status = dladm_write_conf(handle, conf); 611d62bc4baSyz147064 } 612d62bc4baSyz147064 6134ac67f02SAnurag S. Maskey dladm_destroy_conf(handle, conf); 614d62bc4baSyz147064 615d62bc4baSyz147064 done: 616d62bc4baSyz147064 return (status); 617d62bc4baSyz147064 } 618d62bc4baSyz147064 619d62bc4baSyz147064 dladm_status_t 6204ac67f02SAnurag S. Maskey dladm_rename_link(dladm_handle_t handle, const char *link1, const char *link2) 621d62bc4baSyz147064 { 622d62bc4baSyz147064 datalink_id_t linkid1 = DATALINK_INVALID_LINKID; 623d62bc4baSyz147064 datalink_id_t linkid2 = DATALINK_INVALID_LINKID; 624d62bc4baSyz147064 uint32_t flags1, flags2; 625d62bc4baSyz147064 datalink_class_t class1, class2; 626d62bc4baSyz147064 uint32_t media1, media2; 627d62bc4baSyz147064 boolean_t remphy2 = B_FALSE; 628d62bc4baSyz147064 dladm_status_t status; 629d62bc4baSyz147064 6304ac67f02SAnurag S. Maskey (void) dladm_name2info(handle, link1, &linkid1, &flags1, &class1, 6314ac67f02SAnurag S. Maskey &media1); 6324ac67f02SAnurag S. Maskey if ((dladm_name2info(handle, link2, &linkid2, &flags2, &class2, 6334ac67f02SAnurag S. Maskey &media2) == DLADM_STATUS_OK) && (class2 == DATALINK_CLASS_PHYS) && 634d62bc4baSyz147064 (flags2 == DLADM_OPT_PERSIST)) { 635d62bc4baSyz147064 /* 636d62bc4baSyz147064 * see whether link2 is a removed physical link. 637d62bc4baSyz147064 */ 638d62bc4baSyz147064 remphy2 = B_TRUE; 639d62bc4baSyz147064 } 640d62bc4baSyz147064 641d62bc4baSyz147064 if (linkid1 != DATALINK_INVALID_LINKID) { 642d62bc4baSyz147064 if (linkid2 == DATALINK_INVALID_LINKID) { 643d62bc4baSyz147064 /* 644d62bc4baSyz147064 * case 1: rename an existing link to a link that 645d62bc4baSyz147064 * does not exist. 646d62bc4baSyz147064 */ 6474ac67f02SAnurag S. Maskey status = i_dladm_rename_link_c1(handle, linkid1, link1, 6484ac67f02SAnurag S. Maskey link2, flags1); 649d62bc4baSyz147064 } else if (remphy2) { 650d62bc4baSyz147064 /* 651d62bc4baSyz147064 * case 2: rename an available link to a REMOVED 652d62bc4baSyz147064 * physical link. Return failure if link1 is not 653d62bc4baSyz147064 * an active physical link. 654d62bc4baSyz147064 */ 655d62bc4baSyz147064 if ((class1 != class2) || (media1 != media2) || 656d62bc4baSyz147064 !(flags1 & DLADM_OPT_ACTIVE)) { 657d62bc4baSyz147064 status = DLADM_STATUS_BADARG; 658d62bc4baSyz147064 } else { 6594ac67f02SAnurag S. Maskey status = i_dladm_rename_link_c2(handle, linkid1, 660d62bc4baSyz147064 linkid2); 661d62bc4baSyz147064 } 662d62bc4baSyz147064 } else { 663d62bc4baSyz147064 status = DLADM_STATUS_EXIST; 664d62bc4baSyz147064 } 665d62bc4baSyz147064 } else if (remphy2) { 6664ac67f02SAnurag S. Maskey status = i_dladm_rename_link_c3(handle, link1, linkid2); 667d62bc4baSyz147064 } else { 668d62bc4baSyz147064 status = DLADM_STATUS_NOTFOUND; 669d62bc4baSyz147064 } 670d62bc4baSyz147064 return (status); 671d62bc4baSyz147064 } 672d62bc4baSyz147064 673d62bc4baSyz147064 typedef struct consumer_del_phys_arg_s { 674d62bc4baSyz147064 datalink_id_t linkid; 675d62bc4baSyz147064 } consumer_del_phys_arg_t; 676d62bc4baSyz147064 677d62bc4baSyz147064 static int 6784ac67f02SAnurag S. Maskey i_dladm_vlan_link_del(dladm_handle_t handle, datalink_id_t vlanid, void *arg) 679d62bc4baSyz147064 { 680d62bc4baSyz147064 consumer_del_phys_arg_t *del_arg = arg; 681d62bc4baSyz147064 dladm_vlan_attr_t vinfo; 682d62bc4baSyz147064 dladm_status_t status; 683d62bc4baSyz147064 6844ac67f02SAnurag S. Maskey status = dladm_vlan_info(handle, vlanid, &vinfo, DLADM_OPT_PERSIST); 685d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 686d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 687d62bc4baSyz147064 688d62bc4baSyz147064 if (vinfo.dv_linkid == del_arg->linkid) 6894ac67f02SAnurag S. Maskey (void) dladm_vlan_delete(handle, vlanid, DLADM_OPT_PERSIST); 690d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 691d62bc4baSyz147064 } 692d62bc4baSyz147064 693d62bc4baSyz147064 static int 6944ac67f02SAnurag S. Maskey i_dladm_aggr_link_del(dladm_handle_t handle, datalink_id_t aggrid, void *arg) 695d62bc4baSyz147064 { 696d62bc4baSyz147064 consumer_del_phys_arg_t *del_arg = arg; 697d62bc4baSyz147064 dladm_aggr_grp_attr_t ginfo; 698d62bc4baSyz147064 dladm_status_t status; 699d62bc4baSyz147064 dladm_aggr_port_attr_db_t port[1]; 700d62bc4baSyz147064 int i; 701d62bc4baSyz147064 7024ac67f02SAnurag S. Maskey status = dladm_aggr_info(handle, aggrid, &ginfo, DLADM_OPT_PERSIST); 703d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 704d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 705d62bc4baSyz147064 706d62bc4baSyz147064 for (i = 0; i < ginfo.lg_nports; i++) 707d62bc4baSyz147064 if (ginfo.lg_ports[i].lp_linkid == del_arg->linkid) 708d62bc4baSyz147064 break; 709d62bc4baSyz147064 710d62bc4baSyz147064 if (i != ginfo.lg_nports) { 711d62bc4baSyz147064 if (ginfo.lg_nports == 1 && i == 0) { 712d62bc4baSyz147064 consumer_del_phys_arg_t aggr_del_arg; 713d62bc4baSyz147064 714d62bc4baSyz147064 /* 715d62bc4baSyz147064 * First delete all the VLANs on this aggregation, then 716d62bc4baSyz147064 * delete the aggregation itself. 717d62bc4baSyz147064 */ 718d62bc4baSyz147064 aggr_del_arg.linkid = aggrid; 719d62bc4baSyz147064 (void) dladm_walk_datalink_id(i_dladm_vlan_link_del, 7204ac67f02SAnurag S. Maskey handle, &aggr_del_arg, DATALINK_CLASS_VLAN, 721d62bc4baSyz147064 DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 7224ac67f02SAnurag S. Maskey (void) dladm_aggr_delete(handle, aggrid, 7234ac67f02SAnurag S. Maskey DLADM_OPT_PERSIST); 724d62bc4baSyz147064 } else { 725d62bc4baSyz147064 port[0].lp_linkid = del_arg->linkid; 7264ac67f02SAnurag S. Maskey (void) dladm_aggr_remove(handle, aggrid, 1, port, 727d62bc4baSyz147064 DLADM_OPT_PERSIST); 728d62bc4baSyz147064 } 729d62bc4baSyz147064 } 730d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 731d62bc4baSyz147064 } 732d62bc4baSyz147064 733d62bc4baSyz147064 typedef struct del_phys_arg_s { 734d62bc4baSyz147064 dladm_status_t rval; 735d62bc4baSyz147064 } del_phys_arg_t; 736d62bc4baSyz147064 737d62bc4baSyz147064 static int 7384ac67f02SAnurag S. Maskey i_dladm_phys_delete(dladm_handle_t handle, datalink_id_t linkid, void *arg) 739d62bc4baSyz147064 { 740d62bc4baSyz147064 uint32_t flags; 741d62bc4baSyz147064 datalink_class_t class; 742d62bc4baSyz147064 uint32_t media; 743d62bc4baSyz147064 dladm_status_t status = DLADM_STATUS_OK; 744d62bc4baSyz147064 del_phys_arg_t *del_phys_arg = arg; 745d62bc4baSyz147064 consumer_del_phys_arg_t del_arg; 746d62bc4baSyz147064 7474ac67f02SAnurag S. Maskey if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class, 748d62bc4baSyz147064 &media, NULL, 0)) != DLADM_STATUS_OK) { 749d62bc4baSyz147064 goto done; 750d62bc4baSyz147064 } 751d62bc4baSyz147064 752d62bc4baSyz147064 /* 753d62bc4baSyz147064 * see whether this link is a removed physical link. 754d62bc4baSyz147064 */ 755d62bc4baSyz147064 if ((class != DATALINK_CLASS_PHYS) || !(flags & DLADM_OPT_PERSIST) || 756d62bc4baSyz147064 (flags & DLADM_OPT_ACTIVE)) { 757d62bc4baSyz147064 status = DLADM_STATUS_BADARG; 758d62bc4baSyz147064 goto done; 759d62bc4baSyz147064 } 760d62bc4baSyz147064 761d62bc4baSyz147064 if (media == DL_ETHER) { 762d62bc4baSyz147064 del_arg.linkid = linkid; 7634ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(i_dladm_aggr_link_del, handle, 7644ac67f02SAnurag S. Maskey &del_arg, DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, 765d62bc4baSyz147064 DLADM_OPT_PERSIST); 7664ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(i_dladm_vlan_link_del, handle, 7674ac67f02SAnurag S. Maskey &del_arg, DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, 768d62bc4baSyz147064 DLADM_OPT_PERSIST); 769d62bc4baSyz147064 } 770d62bc4baSyz147064 7714ac67f02SAnurag S. Maskey (void) dladm_remove_conf(handle, linkid); 7722b24ab6bSSebastien Roy (void) dladm_destroy_datalink_id(handle, linkid, DLADM_OPT_PERSIST); 773d62bc4baSyz147064 done: 774d62bc4baSyz147064 del_phys_arg->rval = status; 775d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 776d62bc4baSyz147064 } 777d62bc4baSyz147064 778d62bc4baSyz147064 dladm_status_t 7794ac67f02SAnurag S. Maskey dladm_phys_delete(dladm_handle_t handle, datalink_id_t linkid) 780d62bc4baSyz147064 { 781d62bc4baSyz147064 del_phys_arg_t arg = {DLADM_STATUS_OK}; 782d62bc4baSyz147064 783d62bc4baSyz147064 if (linkid == DATALINK_ALL_LINKID) { 7844ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(i_dladm_phys_delete, handle, &arg, 785d62bc4baSyz147064 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, 786d62bc4baSyz147064 DLADM_OPT_PERSIST); 787d62bc4baSyz147064 return (DLADM_STATUS_OK); 788d62bc4baSyz147064 } else { 7894ac67f02SAnurag S. Maskey (void) i_dladm_phys_delete(handle, linkid, &arg); 790d62bc4baSyz147064 return (arg.rval); 791d62bc4baSyz147064 } 792d62bc4baSyz147064 } 793d62bc4baSyz147064 794d62bc4baSyz147064 dladm_status_t 7954ac67f02SAnurag S. Maskey dladm_phys_info(dladm_handle_t handle, datalink_id_t linkid, 7964ac67f02SAnurag S. Maskey dladm_phys_attr_t *dpap, uint32_t flags) 797d62bc4baSyz147064 { 798d62bc4baSyz147064 dladm_status_t status; 799d62bc4baSyz147064 800d62bc4baSyz147064 assert(flags == DLADM_OPT_ACTIVE || flags == DLADM_OPT_PERSIST); 801d62bc4baSyz147064 802d62bc4baSyz147064 switch (flags) { 803d62bc4baSyz147064 case DLADM_OPT_PERSIST: { 804d62bc4baSyz147064 dladm_conf_t conf; 805d62bc4baSyz147064 8064ac67f02SAnurag S. Maskey status = dladm_read_conf(handle, linkid, &conf); 807d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 808d62bc4baSyz147064 return (status); 809d62bc4baSyz147064 8104ac67f02SAnurag S. Maskey status = dladm_get_conf_field(handle, conf, FDEVNAME, 8114ac67f02SAnurag S. Maskey dpap->dp_dev, MAXLINKNAMELEN); 8124ac67f02SAnurag S. Maskey dladm_destroy_conf(handle, conf); 813d62bc4baSyz147064 return (status); 814d62bc4baSyz147064 } 815d62bc4baSyz147064 case DLADM_OPT_ACTIVE: { 816d62bc4baSyz147064 dld_ioc_phys_attr_t dip; 817d62bc4baSyz147064 818d62bc4baSyz147064 dip.dip_linkid = linkid; 8194ac67f02SAnurag S. Maskey if (ioctl(dladm_dld_fd(handle), DLDIOC_PHYS_ATTR, &dip) < 0) { 820d62bc4baSyz147064 status = dladm_errno2status(errno); 821d62bc4baSyz147064 return (status); 822d62bc4baSyz147064 } 823d62bc4baSyz147064 dpap->dp_novanity = dip.dip_novanity; 824d62bc4baSyz147064 (void) strlcpy(dpap->dp_dev, dip.dip_dev, MAXLINKNAMELEN); 825d62bc4baSyz147064 return (DLADM_STATUS_OK); 826d62bc4baSyz147064 } 827d62bc4baSyz147064 default: 828d62bc4baSyz147064 return (DLADM_STATUS_BADARG); 829d62bc4baSyz147064 } 830d62bc4baSyz147064 } 831d62bc4baSyz147064 832d62bc4baSyz147064 typedef struct i_walk_dev_state_s { 833d62bc4baSyz147064 const char *devname; 834d62bc4baSyz147064 datalink_id_t linkid; 835d62bc4baSyz147064 boolean_t found; 836d62bc4baSyz147064 } i_walk_dev_state_t; 837d62bc4baSyz147064 838d62bc4baSyz147064 int 8394ac67f02SAnurag S. Maskey i_dladm_walk_dev2linkid(dladm_handle_t handle, datalink_id_t linkid, void *arg) 840d62bc4baSyz147064 { 841d62bc4baSyz147064 dladm_phys_attr_t dpa; 842d62bc4baSyz147064 dladm_status_t status; 843d62bc4baSyz147064 i_walk_dev_state_t *statep = arg; 844d62bc4baSyz147064 8454ac67f02SAnurag S. Maskey status = dladm_phys_info(handle, linkid, &dpa, DLADM_OPT_PERSIST); 846d62bc4baSyz147064 if ((status == DLADM_STATUS_OK) && 847d62bc4baSyz147064 (strcmp(statep->devname, dpa.dp_dev) == 0)) { 848d62bc4baSyz147064 statep->found = B_TRUE; 849d62bc4baSyz147064 statep->linkid = linkid; 850d62bc4baSyz147064 return (DLADM_WALK_TERMINATE); 851d62bc4baSyz147064 } 852d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 853d62bc4baSyz147064 } 854d62bc4baSyz147064 855d62bc4baSyz147064 /* 856d62bc4baSyz147064 * Get the linkid from the physical device name. 857d62bc4baSyz147064 */ 858d62bc4baSyz147064 dladm_status_t 8594ac67f02SAnurag S. Maskey dladm_dev2linkid(dladm_handle_t handle, const char *devname, 8604ac67f02SAnurag S. Maskey datalink_id_t *linkidp) 861d62bc4baSyz147064 { 862d62bc4baSyz147064 i_walk_dev_state_t state; 863d62bc4baSyz147064 864d62bc4baSyz147064 state.found = B_FALSE; 865d62bc4baSyz147064 state.devname = devname; 866d62bc4baSyz147064 8674ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(i_dladm_walk_dev2linkid, handle, &state, 868d62bc4baSyz147064 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 869d62bc4baSyz147064 if (state.found == B_TRUE) { 870d62bc4baSyz147064 *linkidp = state.linkid; 871d62bc4baSyz147064 return (DLADM_STATUS_OK); 872d62bc4baSyz147064 } else { 873d62bc4baSyz147064 return (dladm_errno2status(ENOENT)); 874d62bc4baSyz147064 } 875d62bc4baSyz147064 } 876d62bc4baSyz147064 877d62bc4baSyz147064 static int 878d62bc4baSyz147064 parse_devname(const char *devname, char *driver, uint_t *ppa, size_t maxlen) 879d62bc4baSyz147064 { 880d62bc4baSyz147064 char *cp, *tp; 881d62bc4baSyz147064 int len; 882d62bc4baSyz147064 883d62bc4baSyz147064 /* 884d62bc4baSyz147064 * device name length must not be 0, and it must end with digit. 885d62bc4baSyz147064 */ 886d62bc4baSyz147064 if (((len = strlen(devname)) == 0) || !isdigit(devname[len - 1])) 887d62bc4baSyz147064 return (EINVAL); 888d62bc4baSyz147064 889d62bc4baSyz147064 (void) strlcpy(driver, devname, maxlen); 890d62bc4baSyz147064 cp = (char *)&driver[len - 1]; 891d62bc4baSyz147064 892d62bc4baSyz147064 for (tp = cp; isdigit(*tp); tp--) { 893d62bc4baSyz147064 if (tp <= driver) 894d62bc4baSyz147064 return (EINVAL); 895d62bc4baSyz147064 } 896d62bc4baSyz147064 897d62bc4baSyz147064 *ppa = atoi(tp + 1); 898d62bc4baSyz147064 *(tp + 1) = '\0'; 899d62bc4baSyz147064 return (0); 900d62bc4baSyz147064 } 901d62bc4baSyz147064 902d62bc4baSyz147064 dladm_status_t 9034ac67f02SAnurag S. Maskey dladm_linkid2legacyname(dladm_handle_t handle, datalink_id_t linkid, char *dev, 9044ac67f02SAnurag S. Maskey size_t len) 905d62bc4baSyz147064 { 906d62bc4baSyz147064 char devname[MAXLINKNAMELEN]; 907d62bc4baSyz147064 uint16_t vid = VLAN_ID_NONE; 908d62bc4baSyz147064 datalink_class_t class; 909d62bc4baSyz147064 dladm_status_t status; 910d62bc4baSyz147064 9114ac67f02SAnurag S. Maskey status = dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, 9124ac67f02SAnurag S. Maskey NULL, 0); 913d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 914d62bc4baSyz147064 goto done; 915d62bc4baSyz147064 916d62bc4baSyz147064 /* 917d62bc4baSyz147064 * If this is a VLAN, we must first determine the class and linkid of 918d62bc4baSyz147064 * the link the VLAN has been created over. 919d62bc4baSyz147064 */ 920d62bc4baSyz147064 if (class == DATALINK_CLASS_VLAN) { 921d62bc4baSyz147064 dladm_vlan_attr_t dva; 922d62bc4baSyz147064 9234ac67f02SAnurag S. Maskey status = dladm_vlan_info(handle, linkid, &dva, 9244ac67f02SAnurag S. Maskey DLADM_OPT_ACTIVE); 925d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 926d62bc4baSyz147064 goto done; 927d62bc4baSyz147064 linkid = dva.dv_linkid; 928d62bc4baSyz147064 vid = dva.dv_vid; 929d62bc4baSyz147064 9304ac67f02SAnurag S. Maskey if ((status = dladm_datalink_id2info(handle, linkid, NULL, 9314ac67f02SAnurag S. Maskey &class, NULL, NULL, 0)) != DLADM_STATUS_OK) { 932d62bc4baSyz147064 goto done; 933d62bc4baSyz147064 } 934d62bc4baSyz147064 } 935d62bc4baSyz147064 936d62bc4baSyz147064 switch (class) { 937d62bc4baSyz147064 case DATALINK_CLASS_AGGR: { 938d62bc4baSyz147064 dladm_aggr_grp_attr_t dga; 939d62bc4baSyz147064 9404ac67f02SAnurag S. Maskey status = dladm_aggr_info(handle, linkid, &dga, 9414ac67f02SAnurag S. Maskey DLADM_OPT_ACTIVE); 942d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 943d62bc4baSyz147064 goto done; 944d62bc4baSyz147064 945d62bc4baSyz147064 if (dga.lg_key == 0) { 946d62bc4baSyz147064 /* 947d62bc4baSyz147064 * If the key was not specified when the aggregation 948d62bc4baSyz147064 * is created, we cannot guess its /dev node name. 949d62bc4baSyz147064 */ 950d62bc4baSyz147064 status = DLADM_STATUS_BADARG; 951d62bc4baSyz147064 goto done; 952d62bc4baSyz147064 } 953d62bc4baSyz147064 (void) snprintf(devname, MAXLINKNAMELEN, "aggr%d", dga.lg_key); 954d62bc4baSyz147064 break; 955d62bc4baSyz147064 } 956d62bc4baSyz147064 case DATALINK_CLASS_PHYS: { 957d62bc4baSyz147064 dladm_phys_attr_t dpa; 958d62bc4baSyz147064 9594ac67f02SAnurag S. Maskey status = dladm_phys_info(handle, linkid, &dpa, 9604ac67f02SAnurag S. Maskey DLADM_OPT_PERSIST); 961d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 962d62bc4baSyz147064 goto done; 963d62bc4baSyz147064 964d62bc4baSyz147064 (void) strlcpy(devname, dpa.dp_dev, MAXLINKNAMELEN); 965d62bc4baSyz147064 break; 966d62bc4baSyz147064 } 967d62bc4baSyz147064 default: 968d62bc4baSyz147064 status = DLADM_STATUS_BADARG; 969d62bc4baSyz147064 goto done; 970d62bc4baSyz147064 } 971d62bc4baSyz147064 972d62bc4baSyz147064 if (vid != VLAN_ID_NONE) { 973d62bc4baSyz147064 char drv[MAXNAMELEN]; 974d62bc4baSyz147064 uint_t ppa; 975d62bc4baSyz147064 976d62bc4baSyz147064 if (parse_devname(devname, drv, &ppa, MAXNAMELEN) != 0) { 977d62bc4baSyz147064 status = DLADM_STATUS_BADARG; 978d62bc4baSyz147064 goto done; 979d62bc4baSyz147064 } 980d62bc4baSyz147064 if (snprintf(dev, len, "%s%d", drv, vid * 1000 + ppa) >= len) 981d62bc4baSyz147064 status = DLADM_STATUS_TOOSMALL; 982d62bc4baSyz147064 } else { 983d62bc4baSyz147064 if (strlcpy(dev, devname, len) >= len) 984d62bc4baSyz147064 status = DLADM_STATUS_TOOSMALL; 985d62bc4baSyz147064 } 986d62bc4baSyz147064 987d62bc4baSyz147064 done: 988d62bc4baSyz147064 return (status); 989f595a68aSyz147064 } 990e7801d59Ssowmini 991e7801d59Ssowmini dladm_status_t 992e7801d59Ssowmini dladm_parselink(const char *dev, char *provider, uint_t *ppa) 993e7801d59Ssowmini { 994e7801d59Ssowmini ifspec_t ifsp; 995e7801d59Ssowmini 996e7801d59Ssowmini if (dev == NULL || !ifparse_ifspec(dev, &ifsp)) 997e7801d59Ssowmini return (DLADM_STATUS_LINKINVAL); 998e7801d59Ssowmini 999e7801d59Ssowmini if (provider != NULL) 1000e7801d59Ssowmini (void) strlcpy(provider, ifsp.ifsp_devnm, DLPI_LINKNAME_MAX); 1001e7801d59Ssowmini 1002e7801d59Ssowmini if (ppa != NULL) 1003e7801d59Ssowmini *ppa = ifsp.ifsp_ppa; 1004e7801d59Ssowmini 1005e7801d59Ssowmini return (DLADM_STATUS_OK); 1006e7801d59Ssowmini } 1007