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*2b24ab6bSSebastien Roy * Copyright 2009 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 514ac67f02SAnurag S. Maskey i_dladm_info(dladm_handle_t handle, const datalink_id_t linkid, 524ac67f02SAnurag S. Maskey dladm_attr_t *dap) 53f595a68aSyz147064 { 54f595a68aSyz147064 dld_ioc_attr_t dia; 55f595a68aSyz147064 56d62bc4baSyz147064 dia.dia_linkid = linkid; 57f595a68aSyz147064 584ac67f02SAnurag 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 674ac67f02SAnurag S. Maskey dladm_usagelog(dladm_handle_t handle, dladm_logtype_t type, 684ac67f02SAnurag 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 754ac67f02SAnurag S. Maskey if (ioctl(dladm_dld_fd(handle), DLDIOC_USAGELOG, log_info) < 0) 76da14cebeSEric Cheng return (DLADM_STATUS_IOERR); 774ac67f02SAnurag S. Maskey 78da14cebeSEric Cheng return (DLADM_STATUS_OK); 79da14cebeSEric Cheng } 80da14cebeSEric Cheng 81da14cebeSEric Cheng dladm_status_t 824ac67f02SAnurag S. Maskey dladm_start_usagelog(dladm_handle_t handle, dladm_logtype_t type, 834ac67f02SAnurag 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 904ac67f02SAnurag S. Maskey return (dladm_usagelog(handle, type, &log_info)); 91da14cebeSEric Cheng } 92da14cebeSEric Cheng 93da14cebeSEric Cheng dladm_status_t 944ac67f02SAnurag 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 1014ac67f02SAnurag 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 1104ac67f02SAnurag 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 1154ac67f02SAnurag 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 1274ac67f02SAnurag S. Maskey dladm_walk(dladm_walkcb_t *fn, dladm_handle_t handle, void *arg, 1284ac67f02SAnurag 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; 1344ac67f02SAnurag 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 1414ac67f02SAnurag 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 { 1444ac67f02SAnurag 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 1574ac67f02SAnurag 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 1904ac67f02SAnurag 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 { 1934ac67f02SAnurag 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 2064ac67f02SAnurag 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 3364ac67f02SAnurag S. Maskey dladm_info(dladm_handle_t handle, datalink_id_t linkid, dladm_attr_t *dap) 337f595a68aSyz147064 { 3384ac67f02SAnurag 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 /* 382d62bc4baSyz147064 * Case 1: rename an existing link1 to a link2 that does not exist. 383d62bc4baSyz147064 * Result: <linkid1, link2> 384d62bc4baSyz147064 */ 385d62bc4baSyz147064 static dladm_status_t 3864ac67f02SAnurag S. Maskey i_dladm_rename_link_c1(dladm_handle_t handle, datalink_id_t linkid1, 3874ac67f02SAnurag S. Maskey const char *link1, const char *link2, uint32_t flags) 388d62bc4baSyz147064 { 389d62bc4baSyz147064 dld_ioc_rename_t dir; 390d62bc4baSyz147064 dladm_status_t status = DLADM_STATUS_OK; 391d62bc4baSyz147064 392d62bc4baSyz147064 /* 393d62bc4baSyz147064 * Link is currently available. Check to see whether anything is 394d62bc4baSyz147064 * holding this link to prevent a rename operation. 395d62bc4baSyz147064 */ 396d62bc4baSyz147064 if (flags & DLADM_OPT_ACTIVE) { 397d62bc4baSyz147064 dir.dir_linkid1 = linkid1; 398d62bc4baSyz147064 dir.dir_linkid2 = DATALINK_INVALID_LINKID; 399d62bc4baSyz147064 (void) strlcpy(dir.dir_link, link2, MAXLINKNAMELEN); 400d62bc4baSyz147064 4014ac67f02SAnurag S. Maskey if (ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir) < 0) { 402d62bc4baSyz147064 status = dladm_errno2status(errno); 403d62bc4baSyz147064 return (status); 404d62bc4baSyz147064 } 405d62bc4baSyz147064 } 406d62bc4baSyz147064 4074ac67f02SAnurag S. Maskey status = dladm_remap_datalink_id(handle, linkid1, link2); 408*2b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK && (flags & DLADM_OPT_ACTIVE)) { 409d62bc4baSyz147064 (void) strlcpy(dir.dir_link, link1, MAXLINKNAMELEN); 4104ac67f02SAnurag S. Maskey (void) ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir); 411d62bc4baSyz147064 } 412d62bc4baSyz147064 return (status); 413d62bc4baSyz147064 } 414d62bc4baSyz147064 415d62bc4baSyz147064 typedef struct link_hold_arg_s { 416d62bc4baSyz147064 datalink_id_t linkid; 417d62bc4baSyz147064 datalink_id_t holder; 418d62bc4baSyz147064 uint32_t flags; 419d62bc4baSyz147064 } link_hold_arg_t; 420d62bc4baSyz147064 421d62bc4baSyz147064 static int 4224ac67f02SAnurag S. Maskey i_dladm_aggr_link_hold(dladm_handle_t handle, datalink_id_t aggrid, void *arg) 423d62bc4baSyz147064 { 424d62bc4baSyz147064 link_hold_arg_t *hold_arg = arg; 425d62bc4baSyz147064 dladm_aggr_grp_attr_t ginfo; 426d62bc4baSyz147064 dladm_status_t status; 427d62bc4baSyz147064 int i; 428d62bc4baSyz147064 4294ac67f02SAnurag S. Maskey status = dladm_aggr_info(handle, aggrid, &ginfo, hold_arg->flags); 430d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 431d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 432d62bc4baSyz147064 433d62bc4baSyz147064 for (i = 0; i < ginfo.lg_nports; i++) { 434d62bc4baSyz147064 if (ginfo.lg_ports[i].lp_linkid == hold_arg->linkid) { 435d62bc4baSyz147064 hold_arg->holder = aggrid; 436d62bc4baSyz147064 return (DLADM_WALK_TERMINATE); 437d62bc4baSyz147064 } 438d62bc4baSyz147064 } 439d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 440d62bc4baSyz147064 } 441d62bc4baSyz147064 442d62bc4baSyz147064 static int 4434ac67f02SAnurag S. Maskey i_dladm_vlan_link_hold(dladm_handle_t handle, datalink_id_t vlanid, void *arg) 444d62bc4baSyz147064 { 445d62bc4baSyz147064 link_hold_arg_t *hold_arg = arg; 446d62bc4baSyz147064 dladm_vlan_attr_t vinfo; 447d62bc4baSyz147064 dladm_status_t status; 448d62bc4baSyz147064 4494ac67f02SAnurag S. Maskey status = dladm_vlan_info(handle, vlanid, &vinfo, hold_arg->flags); 450d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 451d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 452d62bc4baSyz147064 453d62bc4baSyz147064 if (vinfo.dv_linkid == hold_arg->linkid) { 454d62bc4baSyz147064 hold_arg->holder = vlanid; 455d62bc4baSyz147064 return (DLADM_WALK_TERMINATE); 456d62bc4baSyz147064 } 457d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 458d62bc4baSyz147064 } 459d62bc4baSyz147064 460d62bc4baSyz147064 /* 461d62bc4baSyz147064 * Case 2: rename an available physical link link1 to a REMOVED physical link 462d62bc4baSyz147064 * link2. As a result, link1 directly inherits all datalinks configured 463d62bc4baSyz147064 * over link2 (linkid2). 464d62bc4baSyz147064 * Result: <linkid2, link2, link1_phymaj, link1_phyinst, link1_devname, 465d62bc4baSyz147064 * link2_other_attr> 466d62bc4baSyz147064 */ 467d62bc4baSyz147064 static dladm_status_t 4684ac67f02SAnurag S. Maskey i_dladm_rename_link_c2(dladm_handle_t handle, datalink_id_t linkid1, 4694ac67f02SAnurag S. Maskey datalink_id_t linkid2) 470d62bc4baSyz147064 { 471d62bc4baSyz147064 rcm_handle_t *rcm_hdl = NULL; 472d62bc4baSyz147064 nvlist_t *nvl = NULL; 473d62bc4baSyz147064 link_hold_arg_t arg; 474d62bc4baSyz147064 dld_ioc_rename_t dir; 475d62bc4baSyz147064 dladm_conf_t conf1, conf2; 476d62bc4baSyz147064 char devname[MAXLINKNAMELEN]; 477d62bc4baSyz147064 uint64_t phymaj, phyinst; 478d62bc4baSyz147064 dladm_status_t status = DLADM_STATUS_OK; 479d62bc4baSyz147064 480d62bc4baSyz147064 /* 481d62bc4baSyz147064 * First check if linkid1 is associated with any persistent 482d62bc4baSyz147064 * aggregations or VLANs. If yes, return BUSY. 483d62bc4baSyz147064 */ 484d62bc4baSyz147064 arg.linkid = linkid1; 485d62bc4baSyz147064 arg.holder = DATALINK_INVALID_LINKID; 486d62bc4baSyz147064 arg.flags = DLADM_OPT_PERSIST; 4874ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(i_dladm_aggr_link_hold, handle, &arg, 488d62bc4baSyz147064 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 489d62bc4baSyz147064 if (arg.holder != DATALINK_INVALID_LINKID) 490d62bc4baSyz147064 return (DLADM_STATUS_LINKBUSY); 491d62bc4baSyz147064 492d62bc4baSyz147064 arg.flags = DLADM_OPT_PERSIST; 4934ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(i_dladm_vlan_link_hold, handle, &arg, 494d62bc4baSyz147064 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 495d62bc4baSyz147064 if (arg.holder != DATALINK_INVALID_LINKID) 496d62bc4baSyz147064 return (DLADM_STATUS_LINKBUSY); 497d62bc4baSyz147064 498d62bc4baSyz147064 /* 499d62bc4baSyz147064 * Send DLDIOC_RENAME to request to rename link1's linkid to 500d62bc4baSyz147064 * be linkid2. This will check whether link1 is used by any 501d62bc4baSyz147064 * aggregations or VLANs, or is held by any application. If yes, 502d62bc4baSyz147064 * return failure. 503d62bc4baSyz147064 */ 504d62bc4baSyz147064 dir.dir_linkid1 = linkid1; 505d62bc4baSyz147064 dir.dir_linkid2 = linkid2; 5064ac67f02SAnurag S. Maskey if (ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir) < 0) 507d62bc4baSyz147064 status = dladm_errno2status(errno); 508d62bc4baSyz147064 509d62bc4baSyz147064 if (status != DLADM_STATUS_OK) { 510d62bc4baSyz147064 return (status); 511d62bc4baSyz147064 } 512d62bc4baSyz147064 513d62bc4baSyz147064 /* 514d62bc4baSyz147064 * Now change the phymaj, phyinst and devname associated with linkid1 515d62bc4baSyz147064 * to be associated with linkid2. Before doing that, the old active 516d62bc4baSyz147064 * linkprop of linkid1 should be deleted. 517d62bc4baSyz147064 */ 5184ac67f02SAnurag S. Maskey (void) dladm_set_linkprop(handle, linkid1, NULL, NULL, 0, 5194ac67f02SAnurag S. Maskey DLADM_OPT_ACTIVE); 520d62bc4baSyz147064 5214ac67f02SAnurag S. Maskey if (((status = dladm_read_conf(handle, linkid1, &conf1)) != 5224ac67f02SAnurag S. Maskey DLADM_STATUS_OK) || 5234ac67f02SAnurag S. Maskey ((status = dladm_get_conf_field(handle, conf1, FDEVNAME, devname, 524d62bc4baSyz147064 MAXLINKNAMELEN)) != DLADM_STATUS_OK) || 5254ac67f02SAnurag S. Maskey ((status = dladm_get_conf_field(handle, conf1, FPHYMAJ, &phymaj, 526d62bc4baSyz147064 sizeof (uint64_t))) != DLADM_STATUS_OK) || 5274ac67f02SAnurag S. Maskey ((status = dladm_get_conf_field(handle, conf1, FPHYINST, &phyinst, 528d62bc4baSyz147064 sizeof (uint64_t))) != DLADM_STATUS_OK) || 5294ac67f02SAnurag S. Maskey ((status = dladm_read_conf(handle, linkid2, &conf2)) != 5304ac67f02SAnurag S. Maskey DLADM_STATUS_OK)) { 531d62bc4baSyz147064 dir.dir_linkid1 = linkid2; 532d62bc4baSyz147064 dir.dir_linkid2 = linkid1; 5334ac67f02SAnurag S. Maskey (void) dladm_init_linkprop(handle, linkid1, B_FALSE); 5344ac67f02SAnurag S. Maskey (void) ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir); 535d62bc4baSyz147064 return (status); 536d62bc4baSyz147064 } 537d62bc4baSyz147064 5384ac67f02SAnurag S. Maskey dladm_destroy_conf(handle, conf1); 5394ac67f02SAnurag S. Maskey (void) dladm_set_conf_field(handle, conf2, FDEVNAME, DLADM_TYPE_STR, 5404ac67f02SAnurag S. Maskey devname); 5414ac67f02SAnurag S. Maskey (void) dladm_set_conf_field(handle, conf2, FPHYMAJ, DLADM_TYPE_UINT64, 5424ac67f02SAnurag S. Maskey &phymaj); 5434ac67f02SAnurag S. Maskey (void) dladm_set_conf_field(handle, conf2, FPHYINST, 544d62bc4baSyz147064 DLADM_TYPE_UINT64, &phyinst); 5454ac67f02SAnurag S. Maskey (void) dladm_write_conf(handle, conf2); 5464ac67f02SAnurag S. Maskey dladm_destroy_conf(handle, conf2); 547d62bc4baSyz147064 548d62bc4baSyz147064 /* 549d62bc4baSyz147064 * Delete link1 and mark link2 up. 550d62bc4baSyz147064 */ 551*2b24ab6bSSebastien Roy (void) dladm_remove_conf(handle, linkid1); 5524ac67f02SAnurag S. Maskey (void) dladm_destroy_datalink_id(handle, linkid1, DLADM_OPT_ACTIVE | 553d62bc4baSyz147064 DLADM_OPT_PERSIST); 5544ac67f02SAnurag S. Maskey (void) dladm_up_datalink_id(handle, linkid2); 555d62bc4baSyz147064 556d62bc4baSyz147064 /* 557d62bc4baSyz147064 * Now generate the RCM_RESOURCE_LINK_NEW sysevent which can be 558d62bc4baSyz147064 * consumed by the RCM framework to restore all the datalink and 559d62bc4baSyz147064 * IP configuration. 560d62bc4baSyz147064 */ 561d62bc4baSyz147064 status = DLADM_STATUS_FAILED; 562d62bc4baSyz147064 if ((nvlist_alloc(&nvl, 0, 0) != 0) || 563d62bc4baSyz147064 (nvlist_add_uint64(nvl, RCM_NV_LINKID, linkid2) != 0)) { 564d62bc4baSyz147064 goto done; 565d62bc4baSyz147064 } 566d62bc4baSyz147064 567d62bc4baSyz147064 if (rcm_alloc_handle(NULL, 0, NULL, &rcm_hdl) != RCM_SUCCESS) 568d62bc4baSyz147064 goto done; 569d62bc4baSyz147064 570d62bc4baSyz147064 if (rcm_notify_event(rcm_hdl, RCM_RESOURCE_LINK_NEW, 0, nvl, NULL) == 571d62bc4baSyz147064 RCM_SUCCESS) { 572d62bc4baSyz147064 status = DLADM_STATUS_OK; 573d62bc4baSyz147064 } 574d62bc4baSyz147064 575d62bc4baSyz147064 done: 576d62bc4baSyz147064 if (rcm_hdl != NULL) 577d62bc4baSyz147064 (void) rcm_free_handle(rcm_hdl); 578d62bc4baSyz147064 if (nvl != NULL) 579d62bc4baSyz147064 nvlist_free(nvl); 580d62bc4baSyz147064 return (status); 581d62bc4baSyz147064 } 582d62bc4baSyz147064 583d62bc4baSyz147064 /* 584d62bc4baSyz147064 * case 3: rename a non-existent link to a REMOVED physical link. 585d62bc4baSyz147064 * Set the removed physical link's device name to link1, so that 586d62bc4baSyz147064 * when link1 attaches, it inherits all the link configuration of 587d62bc4baSyz147064 * the removed physical link. 588d62bc4baSyz147064 */ 589d62bc4baSyz147064 static dladm_status_t 5904ac67f02SAnurag S. Maskey i_dladm_rename_link_c3(dladm_handle_t handle, const char *link1, 5914ac67f02SAnurag S. Maskey datalink_id_t linkid2) 592d62bc4baSyz147064 { 593d62bc4baSyz147064 dladm_conf_t conf; 594d62bc4baSyz147064 dladm_status_t status; 595d62bc4baSyz147064 596d62bc4baSyz147064 if (!dladm_valid_linkname(link1)) 597d62bc4baSyz147064 return (DLADM_STATUS_LINKINVAL); 598d62bc4baSyz147064 5994ac67f02SAnurag S. Maskey status = dladm_read_conf(handle, linkid2, &conf); 600d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 601d62bc4baSyz147064 goto done; 602d62bc4baSyz147064 6034ac67f02SAnurag S. Maskey if ((status = dladm_set_conf_field(handle, conf, FDEVNAME, 6044ac67f02SAnurag S. Maskey DLADM_TYPE_STR, link1)) == DLADM_STATUS_OK) { 6054ac67f02SAnurag S. Maskey status = dladm_write_conf(handle, conf); 606d62bc4baSyz147064 } 607d62bc4baSyz147064 6084ac67f02SAnurag S. Maskey dladm_destroy_conf(handle, conf); 609d62bc4baSyz147064 610d62bc4baSyz147064 done: 611d62bc4baSyz147064 return (status); 612d62bc4baSyz147064 } 613d62bc4baSyz147064 614d62bc4baSyz147064 dladm_status_t 6154ac67f02SAnurag S. Maskey dladm_rename_link(dladm_handle_t handle, const char *link1, const char *link2) 616d62bc4baSyz147064 { 617d62bc4baSyz147064 datalink_id_t linkid1 = DATALINK_INVALID_LINKID; 618d62bc4baSyz147064 datalink_id_t linkid2 = DATALINK_INVALID_LINKID; 619d62bc4baSyz147064 uint32_t flags1, flags2; 620d62bc4baSyz147064 datalink_class_t class1, class2; 621d62bc4baSyz147064 uint32_t media1, media2; 622d62bc4baSyz147064 boolean_t remphy2 = B_FALSE; 623d62bc4baSyz147064 dladm_status_t status; 624d62bc4baSyz147064 6254ac67f02SAnurag S. Maskey (void) dladm_name2info(handle, link1, &linkid1, &flags1, &class1, 6264ac67f02SAnurag S. Maskey &media1); 6274ac67f02SAnurag S. Maskey if ((dladm_name2info(handle, link2, &linkid2, &flags2, &class2, 6284ac67f02SAnurag S. Maskey &media2) == DLADM_STATUS_OK) && (class2 == DATALINK_CLASS_PHYS) && 629d62bc4baSyz147064 (flags2 == DLADM_OPT_PERSIST)) { 630d62bc4baSyz147064 /* 631d62bc4baSyz147064 * see whether link2 is a removed physical link. 632d62bc4baSyz147064 */ 633d62bc4baSyz147064 remphy2 = B_TRUE; 634d62bc4baSyz147064 } 635d62bc4baSyz147064 636d62bc4baSyz147064 if (linkid1 != DATALINK_INVALID_LINKID) { 637d62bc4baSyz147064 if (linkid2 == DATALINK_INVALID_LINKID) { 638d62bc4baSyz147064 /* 639d62bc4baSyz147064 * case 1: rename an existing link to a link that 640d62bc4baSyz147064 * does not exist. 641d62bc4baSyz147064 */ 6424ac67f02SAnurag S. Maskey status = i_dladm_rename_link_c1(handle, linkid1, link1, 6434ac67f02SAnurag S. Maskey link2, flags1); 644d62bc4baSyz147064 } else if (remphy2) { 645d62bc4baSyz147064 /* 646d62bc4baSyz147064 * case 2: rename an available link to a REMOVED 647d62bc4baSyz147064 * physical link. Return failure if link1 is not 648d62bc4baSyz147064 * an active physical link. 649d62bc4baSyz147064 */ 650d62bc4baSyz147064 if ((class1 != class2) || (media1 != media2) || 651d62bc4baSyz147064 !(flags1 & DLADM_OPT_ACTIVE)) { 652d62bc4baSyz147064 status = DLADM_STATUS_BADARG; 653d62bc4baSyz147064 } else { 6544ac67f02SAnurag S. Maskey status = i_dladm_rename_link_c2(handle, linkid1, 655d62bc4baSyz147064 linkid2); 656d62bc4baSyz147064 } 657d62bc4baSyz147064 } else { 658d62bc4baSyz147064 status = DLADM_STATUS_EXIST; 659d62bc4baSyz147064 } 660d62bc4baSyz147064 } else if (remphy2) { 6614ac67f02SAnurag S. Maskey status = i_dladm_rename_link_c3(handle, link1, linkid2); 662d62bc4baSyz147064 } else { 663d62bc4baSyz147064 status = DLADM_STATUS_NOTFOUND; 664d62bc4baSyz147064 } 665d62bc4baSyz147064 return (status); 666d62bc4baSyz147064 } 667d62bc4baSyz147064 668d62bc4baSyz147064 typedef struct consumer_del_phys_arg_s { 669d62bc4baSyz147064 datalink_id_t linkid; 670d62bc4baSyz147064 } consumer_del_phys_arg_t; 671d62bc4baSyz147064 672d62bc4baSyz147064 static int 6734ac67f02SAnurag S. Maskey i_dladm_vlan_link_del(dladm_handle_t handle, datalink_id_t vlanid, void *arg) 674d62bc4baSyz147064 { 675d62bc4baSyz147064 consumer_del_phys_arg_t *del_arg = arg; 676d62bc4baSyz147064 dladm_vlan_attr_t vinfo; 677d62bc4baSyz147064 dladm_status_t status; 678d62bc4baSyz147064 6794ac67f02SAnurag S. Maskey status = dladm_vlan_info(handle, vlanid, &vinfo, DLADM_OPT_PERSIST); 680d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 681d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 682d62bc4baSyz147064 683d62bc4baSyz147064 if (vinfo.dv_linkid == del_arg->linkid) 6844ac67f02SAnurag S. Maskey (void) dladm_vlan_delete(handle, vlanid, DLADM_OPT_PERSIST); 685d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 686d62bc4baSyz147064 } 687d62bc4baSyz147064 688d62bc4baSyz147064 static int 6894ac67f02SAnurag S. Maskey i_dladm_aggr_link_del(dladm_handle_t handle, datalink_id_t aggrid, void *arg) 690d62bc4baSyz147064 { 691d62bc4baSyz147064 consumer_del_phys_arg_t *del_arg = arg; 692d62bc4baSyz147064 dladm_aggr_grp_attr_t ginfo; 693d62bc4baSyz147064 dladm_status_t status; 694d62bc4baSyz147064 dladm_aggr_port_attr_db_t port[1]; 695d62bc4baSyz147064 int i; 696d62bc4baSyz147064 6974ac67f02SAnurag S. Maskey status = dladm_aggr_info(handle, aggrid, &ginfo, DLADM_OPT_PERSIST); 698d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 699d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 700d62bc4baSyz147064 701d62bc4baSyz147064 for (i = 0; i < ginfo.lg_nports; i++) 702d62bc4baSyz147064 if (ginfo.lg_ports[i].lp_linkid == del_arg->linkid) 703d62bc4baSyz147064 break; 704d62bc4baSyz147064 705d62bc4baSyz147064 if (i != ginfo.lg_nports) { 706d62bc4baSyz147064 if (ginfo.lg_nports == 1 && i == 0) { 707d62bc4baSyz147064 consumer_del_phys_arg_t aggr_del_arg; 708d62bc4baSyz147064 709d62bc4baSyz147064 /* 710d62bc4baSyz147064 * First delete all the VLANs on this aggregation, then 711d62bc4baSyz147064 * delete the aggregation itself. 712d62bc4baSyz147064 */ 713d62bc4baSyz147064 aggr_del_arg.linkid = aggrid; 714d62bc4baSyz147064 (void) dladm_walk_datalink_id(i_dladm_vlan_link_del, 7154ac67f02SAnurag S. Maskey handle, &aggr_del_arg, DATALINK_CLASS_VLAN, 716d62bc4baSyz147064 DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 7174ac67f02SAnurag S. Maskey (void) dladm_aggr_delete(handle, aggrid, 7184ac67f02SAnurag S. Maskey DLADM_OPT_PERSIST); 719d62bc4baSyz147064 } else { 720d62bc4baSyz147064 port[0].lp_linkid = del_arg->linkid; 7214ac67f02SAnurag S. Maskey (void) dladm_aggr_remove(handle, aggrid, 1, port, 722d62bc4baSyz147064 DLADM_OPT_PERSIST); 723d62bc4baSyz147064 } 724d62bc4baSyz147064 } 725d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 726d62bc4baSyz147064 } 727d62bc4baSyz147064 728d62bc4baSyz147064 typedef struct del_phys_arg_s { 729d62bc4baSyz147064 dladm_status_t rval; 730d62bc4baSyz147064 } del_phys_arg_t; 731d62bc4baSyz147064 732d62bc4baSyz147064 static int 7334ac67f02SAnurag S. Maskey i_dladm_phys_delete(dladm_handle_t handle, datalink_id_t linkid, void *arg) 734d62bc4baSyz147064 { 735d62bc4baSyz147064 uint32_t flags; 736d62bc4baSyz147064 datalink_class_t class; 737d62bc4baSyz147064 uint32_t media; 738d62bc4baSyz147064 dladm_status_t status = DLADM_STATUS_OK; 739d62bc4baSyz147064 del_phys_arg_t *del_phys_arg = arg; 740d62bc4baSyz147064 consumer_del_phys_arg_t del_arg; 741d62bc4baSyz147064 7424ac67f02SAnurag S. Maskey if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class, 743d62bc4baSyz147064 &media, NULL, 0)) != DLADM_STATUS_OK) { 744d62bc4baSyz147064 goto done; 745d62bc4baSyz147064 } 746d62bc4baSyz147064 747d62bc4baSyz147064 /* 748d62bc4baSyz147064 * see whether this link is a removed physical link. 749d62bc4baSyz147064 */ 750d62bc4baSyz147064 if ((class != DATALINK_CLASS_PHYS) || !(flags & DLADM_OPT_PERSIST) || 751d62bc4baSyz147064 (flags & DLADM_OPT_ACTIVE)) { 752d62bc4baSyz147064 status = DLADM_STATUS_BADARG; 753d62bc4baSyz147064 goto done; 754d62bc4baSyz147064 } 755d62bc4baSyz147064 756d62bc4baSyz147064 if (media == DL_ETHER) { 757d62bc4baSyz147064 del_arg.linkid = linkid; 7584ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(i_dladm_aggr_link_del, handle, 7594ac67f02SAnurag S. Maskey &del_arg, DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, 760d62bc4baSyz147064 DLADM_OPT_PERSIST); 7614ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(i_dladm_vlan_link_del, handle, 7624ac67f02SAnurag S. Maskey &del_arg, DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, 763d62bc4baSyz147064 DLADM_OPT_PERSIST); 764d62bc4baSyz147064 } 765d62bc4baSyz147064 7664ac67f02SAnurag S. Maskey (void) dladm_remove_conf(handle, linkid); 767*2b24ab6bSSebastien Roy (void) dladm_destroy_datalink_id(handle, linkid, DLADM_OPT_PERSIST); 768d62bc4baSyz147064 done: 769d62bc4baSyz147064 del_phys_arg->rval = status; 770d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 771d62bc4baSyz147064 } 772d62bc4baSyz147064 773d62bc4baSyz147064 dladm_status_t 7744ac67f02SAnurag S. Maskey dladm_phys_delete(dladm_handle_t handle, datalink_id_t linkid) 775d62bc4baSyz147064 { 776d62bc4baSyz147064 del_phys_arg_t arg = {DLADM_STATUS_OK}; 777d62bc4baSyz147064 778d62bc4baSyz147064 if (linkid == DATALINK_ALL_LINKID) { 7794ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(i_dladm_phys_delete, handle, &arg, 780d62bc4baSyz147064 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, 781d62bc4baSyz147064 DLADM_OPT_PERSIST); 782d62bc4baSyz147064 return (DLADM_STATUS_OK); 783d62bc4baSyz147064 } else { 7844ac67f02SAnurag S. Maskey (void) i_dladm_phys_delete(handle, linkid, &arg); 785d62bc4baSyz147064 return (arg.rval); 786d62bc4baSyz147064 } 787d62bc4baSyz147064 } 788d62bc4baSyz147064 789d62bc4baSyz147064 dladm_status_t 7904ac67f02SAnurag S. Maskey dladm_phys_info(dladm_handle_t handle, datalink_id_t linkid, 7914ac67f02SAnurag S. Maskey dladm_phys_attr_t *dpap, uint32_t flags) 792d62bc4baSyz147064 { 793d62bc4baSyz147064 dladm_status_t status; 794d62bc4baSyz147064 795d62bc4baSyz147064 assert(flags == DLADM_OPT_ACTIVE || flags == DLADM_OPT_PERSIST); 796d62bc4baSyz147064 797d62bc4baSyz147064 switch (flags) { 798d62bc4baSyz147064 case DLADM_OPT_PERSIST: { 799d62bc4baSyz147064 dladm_conf_t conf; 800d62bc4baSyz147064 8014ac67f02SAnurag S. Maskey status = dladm_read_conf(handle, linkid, &conf); 802d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 803d62bc4baSyz147064 return (status); 804d62bc4baSyz147064 8054ac67f02SAnurag S. Maskey status = dladm_get_conf_field(handle, conf, FDEVNAME, 8064ac67f02SAnurag S. Maskey dpap->dp_dev, MAXLINKNAMELEN); 8074ac67f02SAnurag S. Maskey dladm_destroy_conf(handle, conf); 808d62bc4baSyz147064 return (status); 809d62bc4baSyz147064 } 810d62bc4baSyz147064 case DLADM_OPT_ACTIVE: { 811d62bc4baSyz147064 dld_ioc_phys_attr_t dip; 812d62bc4baSyz147064 813d62bc4baSyz147064 dip.dip_linkid = linkid; 8144ac67f02SAnurag S. Maskey if (ioctl(dladm_dld_fd(handle), DLDIOC_PHYS_ATTR, &dip) < 0) { 815d62bc4baSyz147064 status = dladm_errno2status(errno); 816d62bc4baSyz147064 return (status); 817d62bc4baSyz147064 } 818d62bc4baSyz147064 dpap->dp_novanity = dip.dip_novanity; 819d62bc4baSyz147064 (void) strlcpy(dpap->dp_dev, dip.dip_dev, MAXLINKNAMELEN); 820d62bc4baSyz147064 return (DLADM_STATUS_OK); 821d62bc4baSyz147064 } 822d62bc4baSyz147064 default: 823d62bc4baSyz147064 return (DLADM_STATUS_BADARG); 824d62bc4baSyz147064 } 825d62bc4baSyz147064 } 826d62bc4baSyz147064 827d62bc4baSyz147064 typedef struct i_walk_dev_state_s { 828d62bc4baSyz147064 const char *devname; 829d62bc4baSyz147064 datalink_id_t linkid; 830d62bc4baSyz147064 boolean_t found; 831d62bc4baSyz147064 } i_walk_dev_state_t; 832d62bc4baSyz147064 833d62bc4baSyz147064 int 8344ac67f02SAnurag S. Maskey i_dladm_walk_dev2linkid(dladm_handle_t handle, datalink_id_t linkid, void *arg) 835d62bc4baSyz147064 { 836d62bc4baSyz147064 dladm_phys_attr_t dpa; 837d62bc4baSyz147064 dladm_status_t status; 838d62bc4baSyz147064 i_walk_dev_state_t *statep = arg; 839d62bc4baSyz147064 8404ac67f02SAnurag S. Maskey status = dladm_phys_info(handle, linkid, &dpa, DLADM_OPT_PERSIST); 841d62bc4baSyz147064 if ((status == DLADM_STATUS_OK) && 842d62bc4baSyz147064 (strcmp(statep->devname, dpa.dp_dev) == 0)) { 843d62bc4baSyz147064 statep->found = B_TRUE; 844d62bc4baSyz147064 statep->linkid = linkid; 845d62bc4baSyz147064 return (DLADM_WALK_TERMINATE); 846d62bc4baSyz147064 } 847d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 848d62bc4baSyz147064 } 849d62bc4baSyz147064 850d62bc4baSyz147064 /* 851d62bc4baSyz147064 * Get the linkid from the physical device name. 852d62bc4baSyz147064 */ 853d62bc4baSyz147064 dladm_status_t 8544ac67f02SAnurag S. Maskey dladm_dev2linkid(dladm_handle_t handle, const char *devname, 8554ac67f02SAnurag S. Maskey datalink_id_t *linkidp) 856d62bc4baSyz147064 { 857d62bc4baSyz147064 i_walk_dev_state_t state; 858d62bc4baSyz147064 859d62bc4baSyz147064 state.found = B_FALSE; 860d62bc4baSyz147064 state.devname = devname; 861d62bc4baSyz147064 8624ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(i_dladm_walk_dev2linkid, handle, &state, 863d62bc4baSyz147064 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 864d62bc4baSyz147064 if (state.found == B_TRUE) { 865d62bc4baSyz147064 *linkidp = state.linkid; 866d62bc4baSyz147064 return (DLADM_STATUS_OK); 867d62bc4baSyz147064 } else { 868d62bc4baSyz147064 return (dladm_errno2status(ENOENT)); 869d62bc4baSyz147064 } 870d62bc4baSyz147064 } 871d62bc4baSyz147064 872d62bc4baSyz147064 static int 873d62bc4baSyz147064 parse_devname(const char *devname, char *driver, uint_t *ppa, size_t maxlen) 874d62bc4baSyz147064 { 875d62bc4baSyz147064 char *cp, *tp; 876d62bc4baSyz147064 int len; 877d62bc4baSyz147064 878d62bc4baSyz147064 /* 879d62bc4baSyz147064 * device name length must not be 0, and it must end with digit. 880d62bc4baSyz147064 */ 881d62bc4baSyz147064 if (((len = strlen(devname)) == 0) || !isdigit(devname[len - 1])) 882d62bc4baSyz147064 return (EINVAL); 883d62bc4baSyz147064 884d62bc4baSyz147064 (void) strlcpy(driver, devname, maxlen); 885d62bc4baSyz147064 cp = (char *)&driver[len - 1]; 886d62bc4baSyz147064 887d62bc4baSyz147064 for (tp = cp; isdigit(*tp); tp--) { 888d62bc4baSyz147064 if (tp <= driver) 889d62bc4baSyz147064 return (EINVAL); 890d62bc4baSyz147064 } 891d62bc4baSyz147064 892d62bc4baSyz147064 *ppa = atoi(tp + 1); 893d62bc4baSyz147064 *(tp + 1) = '\0'; 894d62bc4baSyz147064 return (0); 895d62bc4baSyz147064 } 896d62bc4baSyz147064 897d62bc4baSyz147064 dladm_status_t 8984ac67f02SAnurag S. Maskey dladm_linkid2legacyname(dladm_handle_t handle, datalink_id_t linkid, char *dev, 8994ac67f02SAnurag S. Maskey size_t len) 900d62bc4baSyz147064 { 901d62bc4baSyz147064 char devname[MAXLINKNAMELEN]; 902d62bc4baSyz147064 uint16_t vid = VLAN_ID_NONE; 903d62bc4baSyz147064 datalink_class_t class; 904d62bc4baSyz147064 dladm_status_t status; 905d62bc4baSyz147064 9064ac67f02SAnurag S. Maskey status = dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, 9074ac67f02SAnurag S. Maskey NULL, 0); 908d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 909d62bc4baSyz147064 goto done; 910d62bc4baSyz147064 911d62bc4baSyz147064 /* 912d62bc4baSyz147064 * If this is a VLAN, we must first determine the class and linkid of 913d62bc4baSyz147064 * the link the VLAN has been created over. 914d62bc4baSyz147064 */ 915d62bc4baSyz147064 if (class == DATALINK_CLASS_VLAN) { 916d62bc4baSyz147064 dladm_vlan_attr_t dva; 917d62bc4baSyz147064 9184ac67f02SAnurag S. Maskey status = dladm_vlan_info(handle, linkid, &dva, 9194ac67f02SAnurag S. Maskey DLADM_OPT_ACTIVE); 920d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 921d62bc4baSyz147064 goto done; 922d62bc4baSyz147064 linkid = dva.dv_linkid; 923d62bc4baSyz147064 vid = dva.dv_vid; 924d62bc4baSyz147064 9254ac67f02SAnurag S. Maskey if ((status = dladm_datalink_id2info(handle, linkid, NULL, 9264ac67f02SAnurag S. Maskey &class, NULL, NULL, 0)) != DLADM_STATUS_OK) { 927d62bc4baSyz147064 goto done; 928d62bc4baSyz147064 } 929d62bc4baSyz147064 } 930d62bc4baSyz147064 931d62bc4baSyz147064 switch (class) { 932d62bc4baSyz147064 case DATALINK_CLASS_AGGR: { 933d62bc4baSyz147064 dladm_aggr_grp_attr_t dga; 934d62bc4baSyz147064 9354ac67f02SAnurag S. Maskey status = dladm_aggr_info(handle, linkid, &dga, 9364ac67f02SAnurag S. Maskey DLADM_OPT_ACTIVE); 937d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 938d62bc4baSyz147064 goto done; 939d62bc4baSyz147064 940d62bc4baSyz147064 if (dga.lg_key == 0) { 941d62bc4baSyz147064 /* 942d62bc4baSyz147064 * If the key was not specified when the aggregation 943d62bc4baSyz147064 * is created, we cannot guess its /dev node name. 944d62bc4baSyz147064 */ 945d62bc4baSyz147064 status = DLADM_STATUS_BADARG; 946d62bc4baSyz147064 goto done; 947d62bc4baSyz147064 } 948d62bc4baSyz147064 (void) snprintf(devname, MAXLINKNAMELEN, "aggr%d", dga.lg_key); 949d62bc4baSyz147064 break; 950d62bc4baSyz147064 } 951d62bc4baSyz147064 case DATALINK_CLASS_PHYS: { 952d62bc4baSyz147064 dladm_phys_attr_t dpa; 953d62bc4baSyz147064 9544ac67f02SAnurag S. Maskey status = dladm_phys_info(handle, linkid, &dpa, 9554ac67f02SAnurag S. Maskey DLADM_OPT_PERSIST); 956d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 957d62bc4baSyz147064 goto done; 958d62bc4baSyz147064 959d62bc4baSyz147064 (void) strlcpy(devname, dpa.dp_dev, MAXLINKNAMELEN); 960d62bc4baSyz147064 break; 961d62bc4baSyz147064 } 962d62bc4baSyz147064 default: 963d62bc4baSyz147064 status = DLADM_STATUS_BADARG; 964d62bc4baSyz147064 goto done; 965d62bc4baSyz147064 } 966d62bc4baSyz147064 967d62bc4baSyz147064 if (vid != VLAN_ID_NONE) { 968d62bc4baSyz147064 char drv[MAXNAMELEN]; 969d62bc4baSyz147064 uint_t ppa; 970d62bc4baSyz147064 971d62bc4baSyz147064 if (parse_devname(devname, drv, &ppa, MAXNAMELEN) != 0) { 972d62bc4baSyz147064 status = DLADM_STATUS_BADARG; 973d62bc4baSyz147064 goto done; 974d62bc4baSyz147064 } 975d62bc4baSyz147064 if (snprintf(dev, len, "%s%d", drv, vid * 1000 + ppa) >= len) 976d62bc4baSyz147064 status = DLADM_STATUS_TOOSMALL; 977d62bc4baSyz147064 } else { 978d62bc4baSyz147064 if (strlcpy(dev, devname, len) >= len) 979d62bc4baSyz147064 status = DLADM_STATUS_TOOSMALL; 980d62bc4baSyz147064 } 981d62bc4baSyz147064 982d62bc4baSyz147064 done: 983d62bc4baSyz147064 return (status); 984f595a68aSyz147064 } 985e7801d59Ssowmini 986e7801d59Ssowmini dladm_status_t 987e7801d59Ssowmini dladm_parselink(const char *dev, char *provider, uint_t *ppa) 988e7801d59Ssowmini { 989e7801d59Ssowmini ifspec_t ifsp; 990e7801d59Ssowmini 991e7801d59Ssowmini if (dev == NULL || !ifparse_ifspec(dev, &ifsp)) 992e7801d59Ssowmini return (DLADM_STATUS_LINKINVAL); 993e7801d59Ssowmini 994e7801d59Ssowmini if (provider != NULL) 995e7801d59Ssowmini (void) strlcpy(provider, ifsp.ifsp_devnm, DLPI_LINKNAME_MAX); 996e7801d59Ssowmini 997e7801d59Ssowmini if (ppa != NULL) 998e7801d59Ssowmini *ppa = ifsp.ifsp_ppa; 999e7801d59Ssowmini 1000e7801d59Ssowmini return (DLADM_STATUS_OK); 1001e7801d59Ssowmini } 1002