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