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 /* 221cfa752fSRamaswamy Tummala * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23f595a68aSyz147064 */ 24f595a68aSyz147064 25f595a68aSyz147064 #include <sys/types.h> 26f595a68aSyz147064 #include <unistd.h> 27f595a68aSyz147064 #include <errno.h> 28f595a68aSyz147064 #include <fcntl.h> 29d62bc4baSyz147064 #include <assert.h> 30d62bc4baSyz147064 #include <ctype.h> 31f595a68aSyz147064 #include <strings.h> 32f595a68aSyz147064 #include <sys/stat.h> 33f595a68aSyz147064 #include <sys/dld.h> 34d62bc4baSyz147064 #include <sys/vlan.h> 353bc21d0aSAruna Ramakrishna - Sun Microsystems #include <zone.h> 36d62bc4baSyz147064 #include <librcm.h> 37f595a68aSyz147064 #include <libdlpi.h> 38f595a68aSyz147064 #include <libdevinfo.h> 39d62bc4baSyz147064 #include <libdlaggr.h> 40d62bc4baSyz147064 #include <libdlvlan.h> 410dc2366fSVenugopal Iyer #include <libdlvnic.h> 421cfa752fSRamaswamy Tummala #include <libdlib.h> 43f595a68aSyz147064 #include <libdllink.h> 44d62bc4baSyz147064 #include <libdlmgmt.h> 45f595a68aSyz147064 #include <libdladm_impl.h> 46e7801d59Ssowmini #include <libinetutil.h> 47f595a68aSyz147064 48f595a68aSyz147064 /* 49f595a68aSyz147064 * Return the attributes of the specified datalink from the DLD driver. 50f595a68aSyz147064 */ 51d62bc4baSyz147064 static dladm_status_t 524ac67f02SAnurag S. Maskey i_dladm_info(dladm_handle_t handle, const datalink_id_t linkid, 534ac67f02SAnurag S. Maskey dladm_attr_t *dap) 54f595a68aSyz147064 { 55f595a68aSyz147064 dld_ioc_attr_t dia; 56f595a68aSyz147064 57d62bc4baSyz147064 dia.dia_linkid = linkid; 58f595a68aSyz147064 594ac67f02SAnurag S. Maskey if (ioctl(dladm_dld_fd(handle), DLDIOC_ATTR, &dia) < 0) 60d62bc4baSyz147064 return (dladm_errno2status(errno)); 61f595a68aSyz147064 62f595a68aSyz147064 dap->da_max_sdu = dia.dia_max_sdu; 63f595a68aSyz147064 64d62bc4baSyz147064 return (DLADM_STATUS_OK); 65f595a68aSyz147064 } 66f595a68aSyz147064 67da14cebeSEric Cheng static dladm_status_t 684ac67f02SAnurag S. Maskey dladm_usagelog(dladm_handle_t handle, dladm_logtype_t type, 694ac67f02SAnurag S. Maskey dld_ioc_usagelog_t *log_info) 70da14cebeSEric Cheng { 71da14cebeSEric Cheng if (type == DLADM_LOGTYPE_FLOW) 72da14cebeSEric Cheng log_info->ul_type = MAC_LOGTYPE_FLOW; 73da14cebeSEric Cheng else 74da14cebeSEric Cheng log_info->ul_type = MAC_LOGTYPE_LINK; 75da14cebeSEric Cheng 764ac67f02SAnurag S. Maskey if (ioctl(dladm_dld_fd(handle), DLDIOC_USAGELOG, log_info) < 0) 77da14cebeSEric Cheng return (DLADM_STATUS_IOERR); 784ac67f02SAnurag S. Maskey 79da14cebeSEric Cheng return (DLADM_STATUS_OK); 80da14cebeSEric Cheng } 81da14cebeSEric Cheng 82da14cebeSEric Cheng dladm_status_t 834ac67f02SAnurag S. Maskey dladm_start_usagelog(dladm_handle_t handle, dladm_logtype_t type, 844ac67f02SAnurag S. Maskey uint_t interval) 85da14cebeSEric Cheng { 86da14cebeSEric Cheng dld_ioc_usagelog_t log_info; 87da14cebeSEric Cheng 88da14cebeSEric Cheng log_info.ul_onoff = B_TRUE; 89da14cebeSEric Cheng log_info.ul_interval = interval; 90da14cebeSEric Cheng 914ac67f02SAnurag S. Maskey return (dladm_usagelog(handle, type, &log_info)); 92da14cebeSEric Cheng } 93da14cebeSEric Cheng 94da14cebeSEric Cheng dladm_status_t 954ac67f02SAnurag S. Maskey dladm_stop_usagelog(dladm_handle_t handle, dladm_logtype_t type) 96da14cebeSEric Cheng { 97da14cebeSEric Cheng dld_ioc_usagelog_t log_info; 98da14cebeSEric Cheng 99da14cebeSEric Cheng log_info.ul_onoff = B_FALSE; 100da14cebeSEric Cheng log_info.ul_interval = 0; 101da14cebeSEric Cheng 1024ac67f02SAnurag S. Maskey return (dladm_usagelog(handle, type, &log_info)); 103da14cebeSEric Cheng } 104da14cebeSEric Cheng 105d62bc4baSyz147064 struct i_dladm_walk_arg { 106d62bc4baSyz147064 dladm_walkcb_t *fn; 107d62bc4baSyz147064 void *arg; 108d62bc4baSyz147064 }; 109f595a68aSyz147064 110f595a68aSyz147064 static int 1114ac67f02SAnurag S. Maskey i_dladm_walk(dladm_handle_t handle, datalink_id_t linkid, void *arg) 112f595a68aSyz147064 { 113d62bc4baSyz147064 struct i_dladm_walk_arg *walk_arg = arg; 114d62bc4baSyz147064 char link[MAXLINKNAMELEN]; 115f595a68aSyz147064 1164ac67f02SAnurag S. Maskey if (dladm_datalink_id2info(handle, linkid, NULL, NULL, NULL, link, 117d62bc4baSyz147064 sizeof (link)) == DLADM_STATUS_OK) { 118d62bc4baSyz147064 return (walk_arg->fn(link, walk_arg->arg)); 119f595a68aSyz147064 } 120d62bc4baSyz147064 121d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 122f595a68aSyz147064 } 123f595a68aSyz147064 124f595a68aSyz147064 /* 125d62bc4baSyz147064 * Walk all datalinks. 126f595a68aSyz147064 */ 127d62bc4baSyz147064 dladm_status_t 1284ac67f02SAnurag S. Maskey dladm_walk(dladm_walkcb_t *fn, dladm_handle_t handle, void *arg, 1294ac67f02SAnurag S. Maskey datalink_class_t class, datalink_media_t dmedia, uint32_t flags) 130f595a68aSyz147064 { 131d62bc4baSyz147064 struct i_dladm_walk_arg walk_arg; 132f595a68aSyz147064 133d62bc4baSyz147064 walk_arg.fn = fn; 134d62bc4baSyz147064 walk_arg.arg = arg; 1354ac67f02SAnurag S. Maskey return (dladm_walk_datalink_id(i_dladm_walk, handle, &walk_arg, 136d62bc4baSyz147064 class, dmedia, flags)); 137f595a68aSyz147064 } 138f595a68aSyz147064 139da14cebeSEric Cheng #define MAXGRPPERLINK 64 140da14cebeSEric Cheng 141da14cebeSEric Cheng int 1424ac67f02SAnurag S. Maskey dladm_walk_hwgrp(dladm_handle_t handle, datalink_id_t linkid, void *arg, 143da14cebeSEric Cheng boolean_t (*fn)(void *, dladm_hwgrp_attr_t *)) 144da14cebeSEric Cheng { 1454ac67f02SAnurag S. Maskey int bufsize, ret; 146da14cebeSEric Cheng int nhwgrp = MAXGRPPERLINK; 147da14cebeSEric Cheng dld_ioc_hwgrpget_t *iomp = NULL; 148da14cebeSEric Cheng 149da14cebeSEric Cheng bufsize = sizeof (dld_ioc_hwgrpget_t) + 150da14cebeSEric Cheng nhwgrp * sizeof (dld_hwgrpinfo_t); 151da14cebeSEric Cheng 152da14cebeSEric Cheng if ((iomp = (dld_ioc_hwgrpget_t *)calloc(1, bufsize)) == NULL) 153da14cebeSEric Cheng return (-1); 154da14cebeSEric Cheng 155da14cebeSEric Cheng iomp->dih_size = nhwgrp * sizeof (dld_hwgrpinfo_t); 156da14cebeSEric Cheng iomp->dih_linkid = linkid; 157da14cebeSEric Cheng 1584ac67f02SAnurag S. Maskey ret = ioctl(dladm_dld_fd(handle), DLDIOC_GETHWGRP, iomp); 159da14cebeSEric Cheng if (ret == 0) { 160da14cebeSEric Cheng int i; 1610dc2366fSVenugopal Iyer int j; 162da14cebeSEric Cheng dld_hwgrpinfo_t *dhip; 163da14cebeSEric Cheng dladm_hwgrp_attr_t attr; 164da14cebeSEric Cheng 165da14cebeSEric Cheng dhip = (dld_hwgrpinfo_t *)(iomp + 1); 166da14cebeSEric Cheng for (i = 0; i < iomp->dih_n_groups; i++) { 167da14cebeSEric Cheng bzero(&attr, sizeof (attr)); 168da14cebeSEric Cheng 169da14cebeSEric Cheng (void) strlcpy(attr.hg_link_name, 170da14cebeSEric Cheng dhip->dhi_link_name, sizeof (attr.hg_link_name)); 171da14cebeSEric Cheng attr.hg_grp_num = dhip->dhi_grp_num; 172da14cebeSEric Cheng attr.hg_grp_type = dhip->dhi_grp_type; 173da14cebeSEric Cheng attr.hg_n_rings = dhip->dhi_n_rings; 1740dc2366fSVenugopal Iyer for (j = 0; j < dhip->dhi_n_rings; j++) 1750dc2366fSVenugopal Iyer attr.hg_rings[j] = dhip->dhi_rings[j]; 1760dc2366fSVenugopal Iyer dladm_sort_index_list(attr.hg_rings, attr.hg_n_rings); 177da14cebeSEric Cheng attr.hg_n_clnts = dhip->dhi_n_clnts; 178da14cebeSEric Cheng (void) strlcpy(attr.hg_client_names, 179da14cebeSEric Cheng dhip->dhi_clnts, sizeof (attr.hg_client_names)); 180da14cebeSEric Cheng 181da14cebeSEric Cheng if (!(*fn)(arg, &attr)) 182da14cebeSEric Cheng break; 183da14cebeSEric Cheng dhip++; 184da14cebeSEric Cheng } 185da14cebeSEric Cheng } 186da14cebeSEric Cheng free(iomp); 187da14cebeSEric Cheng return (ret); 188da14cebeSEric Cheng } 189da14cebeSEric Cheng 190da14cebeSEric Cheng /* 191da14cebeSEric Cheng * Invoke the specified callback for each MAC address entry defined on 192da14cebeSEric Cheng * the specified device. 193da14cebeSEric Cheng */ 194da14cebeSEric Cheng int 1954ac67f02SAnurag S. Maskey dladm_walk_macaddr(dladm_handle_t handle, datalink_id_t linkid, void *arg, 196da14cebeSEric Cheng boolean_t (*fn)(void *, dladm_macaddr_attr_t *)) 197da14cebeSEric Cheng { 1984ac67f02SAnurag S. Maskey int bufsize, ret; 199da14cebeSEric Cheng int nmacaddr = 1024; 200da14cebeSEric Cheng dld_ioc_macaddrget_t *iomp = NULL; 201da14cebeSEric Cheng 202da14cebeSEric Cheng bufsize = sizeof (dld_ioc_macaddrget_t) + 203da14cebeSEric Cheng nmacaddr * sizeof (dld_macaddrinfo_t); 204da14cebeSEric Cheng 205da14cebeSEric Cheng if ((iomp = (dld_ioc_macaddrget_t *)calloc(1, bufsize)) == NULL) 206da14cebeSEric Cheng return (-1); 207da14cebeSEric Cheng 208da14cebeSEric Cheng iomp->dig_size = nmacaddr * sizeof (dld_macaddrinfo_t); 209da14cebeSEric Cheng iomp->dig_linkid = linkid; 210da14cebeSEric Cheng 2114ac67f02SAnurag S. Maskey ret = ioctl(dladm_dld_fd(handle), DLDIOC_MACADDRGET, iomp); 212da14cebeSEric Cheng if (ret == 0) { 213da14cebeSEric Cheng int i; 214da14cebeSEric Cheng dld_macaddrinfo_t *dmip; 215da14cebeSEric Cheng dladm_macaddr_attr_t attr; 216da14cebeSEric Cheng 217da14cebeSEric Cheng dmip = (dld_macaddrinfo_t *)(iomp + 1); 218da14cebeSEric Cheng for (i = 0; i < iomp->dig_count; i++) { 219da14cebeSEric Cheng bzero(&attr, sizeof (attr)); 220da14cebeSEric Cheng 221da14cebeSEric Cheng attr.ma_slot = dmip->dmi_slot; 222da14cebeSEric Cheng attr.ma_flags = 0; 223da14cebeSEric Cheng if (dmip->dmi_flags & DLDIOCMACADDR_USED) 224da14cebeSEric Cheng attr.ma_flags |= DLADM_MACADDR_USED; 225da14cebeSEric Cheng bcopy(dmip->dmi_addr, attr.ma_addr, 226da14cebeSEric Cheng dmip->dmi_addrlen); 227da14cebeSEric Cheng attr.ma_addrlen = dmip->dmi_addrlen; 228da14cebeSEric Cheng (void) strlcpy(attr.ma_client_name, 229da14cebeSEric Cheng dmip->dmi_client_name, MAXNAMELEN); 230da14cebeSEric Cheng attr.ma_client_linkid = dmip->dma_client_linkid; 231da14cebeSEric Cheng 232da14cebeSEric Cheng if (!(*fn)(arg, &attr)) 233da14cebeSEric Cheng break; 234da14cebeSEric Cheng dmip++; 235da14cebeSEric Cheng } 236da14cebeSEric Cheng } 237da14cebeSEric Cheng free(iomp); 238da14cebeSEric Cheng return (ret); 239da14cebeSEric Cheng } 240da14cebeSEric Cheng 241f595a68aSyz147064 /* 242d62bc4baSyz147064 * These routines are used by administration tools such as dladm(1M) to 243f595a68aSyz147064 * iterate through the list of MAC interfaces 244f595a68aSyz147064 */ 245f595a68aSyz147064 246f595a68aSyz147064 typedef struct dladm_mac_dev { 247f595a68aSyz147064 char dm_name[MAXNAMELEN]; 248f595a68aSyz147064 struct dladm_mac_dev *dm_next; 249f595a68aSyz147064 } dladm_mac_dev_t; 250f595a68aSyz147064 251f595a68aSyz147064 typedef struct macadm_walk { 252f595a68aSyz147064 dladm_mac_dev_t *dmd_dev_list; 253f595a68aSyz147064 } dladm_mac_walk_t; 254f595a68aSyz147064 255f595a68aSyz147064 /* 256f595a68aSyz147064 * Local callback invoked for each DDI_NT_NET node. 257f595a68aSyz147064 */ 258f595a68aSyz147064 /* ARGSUSED */ 259f595a68aSyz147064 static int 260f595a68aSyz147064 i_dladm_mac_walk(di_node_t node, di_minor_t minor, void *arg) 261f595a68aSyz147064 { 262f595a68aSyz147064 dladm_mac_walk_t *dmwp = arg; 263f595a68aSyz147064 dladm_mac_dev_t *dmdp = dmwp->dmd_dev_list; 264f595a68aSyz147064 dladm_mac_dev_t **last_dmdp = &dmwp->dmd_dev_list; 265f595a68aSyz147064 char mac[MAXNAMELEN]; 266f595a68aSyz147064 267f595a68aSyz147064 (void) snprintf(mac, MAXNAMELEN, "%s%d", 268f595a68aSyz147064 di_driver_name(node), di_instance(node)); 269f595a68aSyz147064 270f595a68aSyz147064 /* 271f595a68aSyz147064 * Skip aggregations. 272f595a68aSyz147064 */ 273f595a68aSyz147064 if (strcmp("aggr", di_driver_name(node)) == 0) 274f595a68aSyz147064 return (DI_WALK_CONTINUE); 275f595a68aSyz147064 276d62bc4baSyz147064 /* 277d62bc4baSyz147064 * Skip softmacs. 278d62bc4baSyz147064 */ 279d62bc4baSyz147064 if (strcmp("softmac", di_driver_name(node)) == 0) 280d62bc4baSyz147064 return (DI_WALK_CONTINUE); 281d62bc4baSyz147064 282f595a68aSyz147064 while (dmdp) { 283f595a68aSyz147064 /* 284f595a68aSyz147064 * Skip duplicates. 285f595a68aSyz147064 */ 286f595a68aSyz147064 if (strcmp(dmdp->dm_name, mac) == 0) 287f595a68aSyz147064 return (DI_WALK_CONTINUE); 288f595a68aSyz147064 289f595a68aSyz147064 last_dmdp = &dmdp->dm_next; 290f595a68aSyz147064 dmdp = dmdp->dm_next; 291f595a68aSyz147064 } 292f595a68aSyz147064 293f595a68aSyz147064 if ((dmdp = malloc(sizeof (*dmdp))) == NULL) 294f595a68aSyz147064 return (DI_WALK_CONTINUE); 295f595a68aSyz147064 296f595a68aSyz147064 (void) strlcpy(dmdp->dm_name, mac, MAXNAMELEN); 297f595a68aSyz147064 dmdp->dm_next = NULL; 298f595a68aSyz147064 *last_dmdp = dmdp; 299f595a68aSyz147064 300f595a68aSyz147064 return (DI_WALK_CONTINUE); 301f595a68aSyz147064 } 302f595a68aSyz147064 303f595a68aSyz147064 /* 304d62bc4baSyz147064 * Invoke the specified callback for each DDI_NT_NET node. 305f595a68aSyz147064 */ 306d62bc4baSyz147064 dladm_status_t 307d62bc4baSyz147064 dladm_mac_walk(int (*fn)(const char *, void *arg), void *arg) 308f595a68aSyz147064 { 309f595a68aSyz147064 di_node_t root; 310f595a68aSyz147064 dladm_mac_walk_t dmw; 311f595a68aSyz147064 dladm_mac_dev_t *dmdp, *next; 312d62bc4baSyz147064 boolean_t done = B_FALSE; 313f595a68aSyz147064 314f595a68aSyz147064 if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) 315d62bc4baSyz147064 return (dladm_errno2status(errno)); 316f595a68aSyz147064 317f595a68aSyz147064 dmw.dmd_dev_list = NULL; 318f595a68aSyz147064 319f595a68aSyz147064 (void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, &dmw, 320f595a68aSyz147064 i_dladm_mac_walk); 321f595a68aSyz147064 322f595a68aSyz147064 di_fini(root); 323f595a68aSyz147064 324f595a68aSyz147064 dmdp = dmw.dmd_dev_list; 325f595a68aSyz147064 for (dmdp = dmw.dmd_dev_list; dmdp != NULL; dmdp = next) { 326f595a68aSyz147064 next = dmdp->dm_next; 327d62bc4baSyz147064 if (!done && 328d62bc4baSyz147064 ((*fn)(dmdp->dm_name, arg) == DLADM_WALK_TERMINATE)) { 329d62bc4baSyz147064 done = B_TRUE; 330d62bc4baSyz147064 } 331f595a68aSyz147064 free(dmdp); 332f595a68aSyz147064 } 333f595a68aSyz147064 334d62bc4baSyz147064 return (DLADM_STATUS_OK); 335f595a68aSyz147064 } 336f595a68aSyz147064 337f595a68aSyz147064 /* 338d62bc4baSyz147064 * Get the current attributes of the specified datalink. 339f595a68aSyz147064 */ 340d62bc4baSyz147064 dladm_status_t 3414ac67f02SAnurag S. Maskey dladm_info(dladm_handle_t handle, datalink_id_t linkid, dladm_attr_t *dap) 342f595a68aSyz147064 { 3434ac67f02SAnurag S. Maskey return (i_dladm_info(handle, linkid, dap)); 344f595a68aSyz147064 } 345f595a68aSyz147064 346f595a68aSyz147064 const char * 347f595a68aSyz147064 dladm_linkstate2str(link_state_t state, char *buf) 348f595a68aSyz147064 { 349f595a68aSyz147064 const char *s; 350f595a68aSyz147064 351f595a68aSyz147064 switch (state) { 352f595a68aSyz147064 case LINK_STATE_UP: 353f595a68aSyz147064 s = "up"; 354f595a68aSyz147064 break; 355f595a68aSyz147064 case LINK_STATE_DOWN: 356f595a68aSyz147064 s = "down"; 357f595a68aSyz147064 break; 358f595a68aSyz147064 default: 359f595a68aSyz147064 s = "unknown"; 360f595a68aSyz147064 break; 361f595a68aSyz147064 } 362f595a68aSyz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 363f595a68aSyz147064 return (buf); 364f595a68aSyz147064 } 365f595a68aSyz147064 366f595a68aSyz147064 const char * 367f595a68aSyz147064 dladm_linkduplex2str(link_duplex_t duplex, char *buf) 368f595a68aSyz147064 { 369f595a68aSyz147064 const char *s; 370f595a68aSyz147064 371f595a68aSyz147064 switch (duplex) { 372f595a68aSyz147064 case LINK_DUPLEX_FULL: 373f595a68aSyz147064 s = "full"; 374f595a68aSyz147064 break; 375f595a68aSyz147064 case LINK_DUPLEX_HALF: 376f595a68aSyz147064 s = "half"; 377f595a68aSyz147064 break; 378f595a68aSyz147064 default: 379f595a68aSyz147064 s = "unknown"; 380f595a68aSyz147064 break; 381f595a68aSyz147064 } 382f595a68aSyz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 383f595a68aSyz147064 return (buf); 384f595a68aSyz147064 } 385f595a68aSyz147064 386f595a68aSyz147064 /* 387d62bc4baSyz147064 * Case 1: rename an existing link1 to a link2 that does not exist. 388d62bc4baSyz147064 * Result: <linkid1, link2> 389d62bc4baSyz147064 */ 390d62bc4baSyz147064 static dladm_status_t 3914ac67f02SAnurag S. Maskey i_dladm_rename_link_c1(dladm_handle_t handle, datalink_id_t linkid1, 3924ac67f02SAnurag S. Maskey const char *link1, const char *link2, uint32_t flags) 393d62bc4baSyz147064 { 394d62bc4baSyz147064 dld_ioc_rename_t dir; 395d62bc4baSyz147064 dladm_status_t status = DLADM_STATUS_OK; 396d62bc4baSyz147064 397d62bc4baSyz147064 /* 398d62bc4baSyz147064 * Link is currently available. Check to see whether anything is 399d62bc4baSyz147064 * holding this link to prevent a rename operation. 400d62bc4baSyz147064 */ 401d62bc4baSyz147064 if (flags & DLADM_OPT_ACTIVE) { 402d62bc4baSyz147064 dir.dir_linkid1 = linkid1; 403d62bc4baSyz147064 dir.dir_linkid2 = DATALINK_INVALID_LINKID; 404d62bc4baSyz147064 (void) strlcpy(dir.dir_link, link2, MAXLINKNAMELEN); 405d62bc4baSyz147064 4064ac67f02SAnurag S. Maskey if (ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir) < 0) { 407d62bc4baSyz147064 status = dladm_errno2status(errno); 408d62bc4baSyz147064 return (status); 409d62bc4baSyz147064 } 410d62bc4baSyz147064 } 411d62bc4baSyz147064 4124ac67f02SAnurag S. Maskey status = dladm_remap_datalink_id(handle, linkid1, link2); 4132b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK && (flags & DLADM_OPT_ACTIVE)) { 414d62bc4baSyz147064 (void) strlcpy(dir.dir_link, link1, MAXLINKNAMELEN); 4154ac67f02SAnurag S. Maskey (void) ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir); 416d62bc4baSyz147064 } 417d62bc4baSyz147064 return (status); 418d62bc4baSyz147064 } 419d62bc4baSyz147064 420d62bc4baSyz147064 typedef struct link_hold_arg_s { 421d62bc4baSyz147064 datalink_id_t linkid; 422d62bc4baSyz147064 datalink_id_t holder; 423d62bc4baSyz147064 uint32_t flags; 424d62bc4baSyz147064 } link_hold_arg_t; 425d62bc4baSyz147064 426d62bc4baSyz147064 static int 4274ac67f02SAnurag S. Maskey i_dladm_aggr_link_hold(dladm_handle_t handle, datalink_id_t aggrid, void *arg) 428d62bc4baSyz147064 { 429d62bc4baSyz147064 link_hold_arg_t *hold_arg = arg; 430d62bc4baSyz147064 dladm_aggr_grp_attr_t ginfo; 431d62bc4baSyz147064 dladm_status_t status; 432d62bc4baSyz147064 int i; 433d62bc4baSyz147064 4344ac67f02SAnurag S. Maskey status = dladm_aggr_info(handle, aggrid, &ginfo, hold_arg->flags); 435d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 436d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 437d62bc4baSyz147064 438d62bc4baSyz147064 for (i = 0; i < ginfo.lg_nports; i++) { 439d62bc4baSyz147064 if (ginfo.lg_ports[i].lp_linkid == hold_arg->linkid) { 440d62bc4baSyz147064 hold_arg->holder = aggrid; 441d62bc4baSyz147064 return (DLADM_WALK_TERMINATE); 442d62bc4baSyz147064 } 443d62bc4baSyz147064 } 444d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 445d62bc4baSyz147064 } 446d62bc4baSyz147064 447d62bc4baSyz147064 static int 4484ac67f02SAnurag S. Maskey i_dladm_vlan_link_hold(dladm_handle_t handle, datalink_id_t vlanid, void *arg) 449d62bc4baSyz147064 { 450d62bc4baSyz147064 link_hold_arg_t *hold_arg = arg; 451d62bc4baSyz147064 dladm_vlan_attr_t vinfo; 452d62bc4baSyz147064 dladm_status_t status; 453d62bc4baSyz147064 4544ac67f02SAnurag S. Maskey status = dladm_vlan_info(handle, vlanid, &vinfo, hold_arg->flags); 455d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 456d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 457d62bc4baSyz147064 458d62bc4baSyz147064 if (vinfo.dv_linkid == hold_arg->linkid) { 459d62bc4baSyz147064 hold_arg->holder = vlanid; 460d62bc4baSyz147064 return (DLADM_WALK_TERMINATE); 461d62bc4baSyz147064 } 462d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 463d62bc4baSyz147064 } 464d62bc4baSyz147064 465d62bc4baSyz147064 /* 466d62bc4baSyz147064 * Case 2: rename an available physical link link1 to a REMOVED physical link 467d62bc4baSyz147064 * link2. As a result, link1 directly inherits all datalinks configured 468d62bc4baSyz147064 * over link2 (linkid2). 469d62bc4baSyz147064 * Result: <linkid2, link2, link1_phymaj, link1_phyinst, link1_devname, 470d62bc4baSyz147064 * link2_other_attr> 471d62bc4baSyz147064 */ 472d62bc4baSyz147064 static dladm_status_t 4734ac67f02SAnurag S. Maskey i_dladm_rename_link_c2(dladm_handle_t handle, datalink_id_t linkid1, 4744ac67f02SAnurag S. Maskey datalink_id_t linkid2) 475d62bc4baSyz147064 { 476d62bc4baSyz147064 rcm_handle_t *rcm_hdl = NULL; 477d62bc4baSyz147064 nvlist_t *nvl = NULL; 478d62bc4baSyz147064 link_hold_arg_t arg; 479d62bc4baSyz147064 dld_ioc_rename_t dir; 480d62bc4baSyz147064 dladm_conf_t conf1, conf2; 481d62bc4baSyz147064 char devname[MAXLINKNAMELEN]; 482d62bc4baSyz147064 uint64_t phymaj, phyinst; 483d62bc4baSyz147064 dladm_status_t status = DLADM_STATUS_OK; 484d62bc4baSyz147064 485d62bc4baSyz147064 /* 486d62bc4baSyz147064 * First check if linkid1 is associated with any persistent 487d62bc4baSyz147064 * aggregations or VLANs. If yes, return BUSY. 488d62bc4baSyz147064 */ 489d62bc4baSyz147064 arg.linkid = linkid1; 490d62bc4baSyz147064 arg.holder = DATALINK_INVALID_LINKID; 491d62bc4baSyz147064 arg.flags = DLADM_OPT_PERSIST; 4924ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(i_dladm_aggr_link_hold, handle, &arg, 493d62bc4baSyz147064 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 494d62bc4baSyz147064 if (arg.holder != DATALINK_INVALID_LINKID) 495d62bc4baSyz147064 return (DLADM_STATUS_LINKBUSY); 496d62bc4baSyz147064 497d62bc4baSyz147064 arg.flags = DLADM_OPT_PERSIST; 4984ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(i_dladm_vlan_link_hold, handle, &arg, 499d62bc4baSyz147064 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 500d62bc4baSyz147064 if (arg.holder != DATALINK_INVALID_LINKID) 501d62bc4baSyz147064 return (DLADM_STATUS_LINKBUSY); 502d62bc4baSyz147064 503d62bc4baSyz147064 /* 504d62bc4baSyz147064 * Send DLDIOC_RENAME to request to rename link1's linkid to 505d62bc4baSyz147064 * be linkid2. This will check whether link1 is used by any 506d62bc4baSyz147064 * aggregations or VLANs, or is held by any application. If yes, 507d62bc4baSyz147064 * return failure. 508d62bc4baSyz147064 */ 509d62bc4baSyz147064 dir.dir_linkid1 = linkid1; 510d62bc4baSyz147064 dir.dir_linkid2 = linkid2; 5114ac67f02SAnurag S. Maskey if (ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir) < 0) 512d62bc4baSyz147064 status = dladm_errno2status(errno); 513d62bc4baSyz147064 514d62bc4baSyz147064 if (status != DLADM_STATUS_OK) { 515d62bc4baSyz147064 return (status); 516d62bc4baSyz147064 } 517d62bc4baSyz147064 518d62bc4baSyz147064 /* 519d62bc4baSyz147064 * Now change the phymaj, phyinst and devname associated with linkid1 520d62bc4baSyz147064 * to be associated with linkid2. Before doing that, the old active 521d62bc4baSyz147064 * linkprop of linkid1 should be deleted. 522d62bc4baSyz147064 */ 5234ac67f02SAnurag S. Maskey (void) dladm_set_linkprop(handle, linkid1, NULL, NULL, 0, 5244ac67f02SAnurag S. Maskey DLADM_OPT_ACTIVE); 525d62bc4baSyz147064 526*32715170SCathy Zhou if (((status = dladm_getsnap_conf(handle, linkid1, &conf1)) != 5274ac67f02SAnurag S. Maskey DLADM_STATUS_OK) || 5284ac67f02SAnurag S. Maskey ((status = dladm_get_conf_field(handle, conf1, FDEVNAME, devname, 529d62bc4baSyz147064 MAXLINKNAMELEN)) != DLADM_STATUS_OK) || 5304ac67f02SAnurag S. Maskey ((status = dladm_get_conf_field(handle, conf1, FPHYMAJ, &phymaj, 531d62bc4baSyz147064 sizeof (uint64_t))) != DLADM_STATUS_OK) || 5324ac67f02SAnurag S. Maskey ((status = dladm_get_conf_field(handle, conf1, FPHYINST, &phyinst, 533d62bc4baSyz147064 sizeof (uint64_t))) != DLADM_STATUS_OK) || 534*32715170SCathy Zhou ((status = dladm_open_conf(handle, linkid2, &conf2)) != 5354ac67f02SAnurag S. Maskey DLADM_STATUS_OK)) { 536d62bc4baSyz147064 dir.dir_linkid1 = linkid2; 537d62bc4baSyz147064 dir.dir_linkid2 = linkid1; 5384ac67f02SAnurag S. Maskey (void) dladm_init_linkprop(handle, linkid1, B_FALSE); 5394ac67f02SAnurag S. Maskey (void) ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir); 540d62bc4baSyz147064 return (status); 541d62bc4baSyz147064 } 542d62bc4baSyz147064 5434ac67f02SAnurag S. Maskey dladm_destroy_conf(handle, conf1); 5444ac67f02SAnurag S. Maskey (void) dladm_set_conf_field(handle, conf2, FDEVNAME, DLADM_TYPE_STR, 5454ac67f02SAnurag S. Maskey devname); 5464ac67f02SAnurag S. Maskey (void) dladm_set_conf_field(handle, conf2, FPHYMAJ, DLADM_TYPE_UINT64, 5474ac67f02SAnurag S. Maskey &phymaj); 5484ac67f02SAnurag S. Maskey (void) dladm_set_conf_field(handle, conf2, FPHYINST, 549d62bc4baSyz147064 DLADM_TYPE_UINT64, &phyinst); 5504ac67f02SAnurag S. Maskey (void) dladm_write_conf(handle, conf2); 5514ac67f02SAnurag S. Maskey dladm_destroy_conf(handle, conf2); 552d62bc4baSyz147064 553d62bc4baSyz147064 /* 554d62bc4baSyz147064 * Delete link1 and mark link2 up. 555d62bc4baSyz147064 */ 5562b24ab6bSSebastien Roy (void) dladm_remove_conf(handle, linkid1); 5574ac67f02SAnurag S. Maskey (void) dladm_destroy_datalink_id(handle, linkid1, DLADM_OPT_ACTIVE | 558d62bc4baSyz147064 DLADM_OPT_PERSIST); 5594ac67f02SAnurag S. Maskey (void) dladm_up_datalink_id(handle, linkid2); 560d62bc4baSyz147064 561d62bc4baSyz147064 /* 562d62bc4baSyz147064 * Now generate the RCM_RESOURCE_LINK_NEW sysevent which can be 563d62bc4baSyz147064 * consumed by the RCM framework to restore all the datalink and 564d62bc4baSyz147064 * IP configuration. 565d62bc4baSyz147064 */ 566d62bc4baSyz147064 status = DLADM_STATUS_FAILED; 567d62bc4baSyz147064 if ((nvlist_alloc(&nvl, 0, 0) != 0) || 568d62bc4baSyz147064 (nvlist_add_uint64(nvl, RCM_NV_LINKID, linkid2) != 0)) { 569d62bc4baSyz147064 goto done; 570d62bc4baSyz147064 } 571d62bc4baSyz147064 572d62bc4baSyz147064 if (rcm_alloc_handle(NULL, 0, NULL, &rcm_hdl) != RCM_SUCCESS) 573d62bc4baSyz147064 goto done; 574d62bc4baSyz147064 575d62bc4baSyz147064 if (rcm_notify_event(rcm_hdl, RCM_RESOURCE_LINK_NEW, 0, nvl, NULL) == 576d62bc4baSyz147064 RCM_SUCCESS) { 577d62bc4baSyz147064 status = DLADM_STATUS_OK; 578d62bc4baSyz147064 } 579d62bc4baSyz147064 580d62bc4baSyz147064 done: 581d62bc4baSyz147064 if (rcm_hdl != NULL) 582d62bc4baSyz147064 (void) rcm_free_handle(rcm_hdl); 583d62bc4baSyz147064 nvlist_free(nvl); 584d62bc4baSyz147064 return (status); 585d62bc4baSyz147064 } 586d62bc4baSyz147064 587d62bc4baSyz147064 /* 588d62bc4baSyz147064 * case 3: rename a non-existent link to a REMOVED physical link. 589d62bc4baSyz147064 * Set the removed physical link's device name to link1, so that 590d62bc4baSyz147064 * when link1 attaches, it inherits all the link configuration of 591d62bc4baSyz147064 * the removed physical link. 592d62bc4baSyz147064 */ 593d62bc4baSyz147064 static dladm_status_t 5944ac67f02SAnurag S. Maskey i_dladm_rename_link_c3(dladm_handle_t handle, const char *link1, 5954ac67f02SAnurag S. Maskey datalink_id_t linkid2) 596d62bc4baSyz147064 { 597d62bc4baSyz147064 dladm_conf_t conf; 598d62bc4baSyz147064 dladm_status_t status; 599d62bc4baSyz147064 600d62bc4baSyz147064 if (!dladm_valid_linkname(link1)) 601d62bc4baSyz147064 return (DLADM_STATUS_LINKINVAL); 602d62bc4baSyz147064 603*32715170SCathy Zhou status = dladm_open_conf(handle, linkid2, &conf); 604d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 605d62bc4baSyz147064 goto done; 606d62bc4baSyz147064 6074ac67f02SAnurag S. Maskey if ((status = dladm_set_conf_field(handle, conf, FDEVNAME, 6084ac67f02SAnurag S. Maskey DLADM_TYPE_STR, link1)) == DLADM_STATUS_OK) { 6094ac67f02SAnurag S. Maskey status = dladm_write_conf(handle, conf); 610d62bc4baSyz147064 } 611d62bc4baSyz147064 6124ac67f02SAnurag S. Maskey dladm_destroy_conf(handle, conf); 613d62bc4baSyz147064 614d62bc4baSyz147064 done: 615d62bc4baSyz147064 return (status); 616d62bc4baSyz147064 } 617d62bc4baSyz147064 618d62bc4baSyz147064 dladm_status_t 6194ac67f02SAnurag S. Maskey dladm_rename_link(dladm_handle_t handle, const char *link1, const char *link2) 620d62bc4baSyz147064 { 621d62bc4baSyz147064 datalink_id_t linkid1 = DATALINK_INVALID_LINKID; 622d62bc4baSyz147064 datalink_id_t linkid2 = DATALINK_INVALID_LINKID; 623d62bc4baSyz147064 uint32_t flags1, flags2; 624d62bc4baSyz147064 datalink_class_t class1, class2; 625d62bc4baSyz147064 uint32_t media1, media2; 626d62bc4baSyz147064 boolean_t remphy2 = B_FALSE; 627d62bc4baSyz147064 dladm_status_t status; 628d62bc4baSyz147064 6294ac67f02SAnurag S. Maskey (void) dladm_name2info(handle, link1, &linkid1, &flags1, &class1, 6304ac67f02SAnurag S. Maskey &media1); 6314ac67f02SAnurag S. Maskey if ((dladm_name2info(handle, link2, &linkid2, &flags2, &class2, 6324ac67f02SAnurag S. Maskey &media2) == DLADM_STATUS_OK) && (class2 == DATALINK_CLASS_PHYS) && 633d62bc4baSyz147064 (flags2 == DLADM_OPT_PERSIST)) { 634d62bc4baSyz147064 /* 635d62bc4baSyz147064 * see whether link2 is a removed physical link. 636d62bc4baSyz147064 */ 637d62bc4baSyz147064 remphy2 = B_TRUE; 638d62bc4baSyz147064 } 639d62bc4baSyz147064 640d62bc4baSyz147064 if (linkid1 != DATALINK_INVALID_LINKID) { 641d62bc4baSyz147064 if (linkid2 == DATALINK_INVALID_LINKID) { 642d62bc4baSyz147064 /* 643d62bc4baSyz147064 * case 1: rename an existing link to a link that 644d62bc4baSyz147064 * does not exist. 645d62bc4baSyz147064 */ 6464ac67f02SAnurag S. Maskey status = i_dladm_rename_link_c1(handle, linkid1, link1, 6474ac67f02SAnurag S. Maskey link2, flags1); 648d62bc4baSyz147064 } else if (remphy2) { 649d62bc4baSyz147064 /* 650d62bc4baSyz147064 * case 2: rename an available link to a REMOVED 651d62bc4baSyz147064 * physical link. Return failure if link1 is not 652d62bc4baSyz147064 * an active physical link. 653d62bc4baSyz147064 */ 654d62bc4baSyz147064 if ((class1 != class2) || (media1 != media2) || 655d62bc4baSyz147064 !(flags1 & DLADM_OPT_ACTIVE)) { 656d62bc4baSyz147064 status = DLADM_STATUS_BADARG; 657d62bc4baSyz147064 } else { 6584ac67f02SAnurag S. Maskey status = i_dladm_rename_link_c2(handle, linkid1, 659d62bc4baSyz147064 linkid2); 660d62bc4baSyz147064 } 661d62bc4baSyz147064 } else { 662d62bc4baSyz147064 status = DLADM_STATUS_EXIST; 663d62bc4baSyz147064 } 664d62bc4baSyz147064 } else if (remphy2) { 6654ac67f02SAnurag S. Maskey status = i_dladm_rename_link_c3(handle, link1, linkid2); 666d62bc4baSyz147064 } else { 667d62bc4baSyz147064 status = DLADM_STATUS_NOTFOUND; 668d62bc4baSyz147064 } 669d62bc4baSyz147064 return (status); 670d62bc4baSyz147064 } 671d62bc4baSyz147064 672d62bc4baSyz147064 typedef struct consumer_del_phys_arg_s { 673d62bc4baSyz147064 datalink_id_t linkid; 674d62bc4baSyz147064 } consumer_del_phys_arg_t; 675d62bc4baSyz147064 676d62bc4baSyz147064 static int 6774ac67f02SAnurag S. Maskey i_dladm_vlan_link_del(dladm_handle_t handle, datalink_id_t vlanid, void *arg) 678d62bc4baSyz147064 { 679d62bc4baSyz147064 consumer_del_phys_arg_t *del_arg = arg; 680d62bc4baSyz147064 dladm_vlan_attr_t vinfo; 681d62bc4baSyz147064 dladm_status_t status; 682d62bc4baSyz147064 6834ac67f02SAnurag S. Maskey status = dladm_vlan_info(handle, vlanid, &vinfo, DLADM_OPT_PERSIST); 684d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 685d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 686d62bc4baSyz147064 687d62bc4baSyz147064 if (vinfo.dv_linkid == del_arg->linkid) 6884ac67f02SAnurag S. Maskey (void) dladm_vlan_delete(handle, vlanid, DLADM_OPT_PERSIST); 689d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 690d62bc4baSyz147064 } 691d62bc4baSyz147064 692d62bc4baSyz147064 static int 6931cfa752fSRamaswamy Tummala i_dladm_part_link_del(dladm_handle_t handle, datalink_id_t partid, void *arg) 6941cfa752fSRamaswamy Tummala { 6951cfa752fSRamaswamy Tummala consumer_del_phys_arg_t *del_arg = arg; 6961cfa752fSRamaswamy Tummala dladm_part_attr_t pinfo; 6971cfa752fSRamaswamy Tummala dladm_status_t status; 6981cfa752fSRamaswamy Tummala 6991cfa752fSRamaswamy Tummala status = dladm_part_info(handle, partid, &pinfo, DLADM_OPT_PERSIST); 7001cfa752fSRamaswamy Tummala if (status != DLADM_STATUS_OK) 7011cfa752fSRamaswamy Tummala return (DLADM_WALK_CONTINUE); 7021cfa752fSRamaswamy Tummala 7031cfa752fSRamaswamy Tummala if (pinfo.dia_physlinkid == del_arg->linkid) 7041cfa752fSRamaswamy Tummala (void) dladm_part_delete(handle, partid, DLADM_OPT_PERSIST); 7051cfa752fSRamaswamy Tummala return (DLADM_WALK_CONTINUE); 7061cfa752fSRamaswamy Tummala } 7071cfa752fSRamaswamy Tummala 7081cfa752fSRamaswamy Tummala static int 7094ac67f02SAnurag S. Maskey i_dladm_aggr_link_del(dladm_handle_t handle, datalink_id_t aggrid, void *arg) 710d62bc4baSyz147064 { 711d62bc4baSyz147064 consumer_del_phys_arg_t *del_arg = arg; 712d62bc4baSyz147064 dladm_aggr_grp_attr_t ginfo; 713d62bc4baSyz147064 dladm_status_t status; 714d62bc4baSyz147064 dladm_aggr_port_attr_db_t port[1]; 715d62bc4baSyz147064 int i; 716d62bc4baSyz147064 7174ac67f02SAnurag S. Maskey status = dladm_aggr_info(handle, aggrid, &ginfo, DLADM_OPT_PERSIST); 718d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 719d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 720d62bc4baSyz147064 721d62bc4baSyz147064 for (i = 0; i < ginfo.lg_nports; i++) 722d62bc4baSyz147064 if (ginfo.lg_ports[i].lp_linkid == del_arg->linkid) 723d62bc4baSyz147064 break; 724d62bc4baSyz147064 725d62bc4baSyz147064 if (i != ginfo.lg_nports) { 726d62bc4baSyz147064 if (ginfo.lg_nports == 1 && i == 0) { 727d62bc4baSyz147064 consumer_del_phys_arg_t aggr_del_arg; 728d62bc4baSyz147064 729d62bc4baSyz147064 /* 730d62bc4baSyz147064 * First delete all the VLANs on this aggregation, then 731d62bc4baSyz147064 * delete the aggregation itself. 732d62bc4baSyz147064 */ 733d62bc4baSyz147064 aggr_del_arg.linkid = aggrid; 734d62bc4baSyz147064 (void) dladm_walk_datalink_id(i_dladm_vlan_link_del, 7354ac67f02SAnurag S. Maskey handle, &aggr_del_arg, DATALINK_CLASS_VLAN, 736d62bc4baSyz147064 DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 7374ac67f02SAnurag S. Maskey (void) dladm_aggr_delete(handle, aggrid, 7384ac67f02SAnurag S. Maskey DLADM_OPT_PERSIST); 739d62bc4baSyz147064 } else { 740d62bc4baSyz147064 port[0].lp_linkid = del_arg->linkid; 7414ac67f02SAnurag S. Maskey (void) dladm_aggr_remove(handle, aggrid, 1, port, 742d62bc4baSyz147064 DLADM_OPT_PERSIST); 743d62bc4baSyz147064 } 744d62bc4baSyz147064 } 745d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 746d62bc4baSyz147064 } 747d62bc4baSyz147064 748d62bc4baSyz147064 typedef struct del_phys_arg_s { 749d62bc4baSyz147064 dladm_status_t rval; 750d62bc4baSyz147064 } del_phys_arg_t; 751d62bc4baSyz147064 752d62bc4baSyz147064 static int 7534ac67f02SAnurag S. Maskey i_dladm_phys_delete(dladm_handle_t handle, datalink_id_t linkid, void *arg) 754d62bc4baSyz147064 { 755d62bc4baSyz147064 uint32_t flags; 756d62bc4baSyz147064 datalink_class_t class; 757d62bc4baSyz147064 uint32_t media; 758d62bc4baSyz147064 dladm_status_t status = DLADM_STATUS_OK; 759d62bc4baSyz147064 del_phys_arg_t *del_phys_arg = arg; 760d62bc4baSyz147064 consumer_del_phys_arg_t del_arg; 761d62bc4baSyz147064 7624ac67f02SAnurag S. Maskey if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class, 763d62bc4baSyz147064 &media, NULL, 0)) != DLADM_STATUS_OK) { 764d62bc4baSyz147064 goto done; 765d62bc4baSyz147064 } 766d62bc4baSyz147064 767d62bc4baSyz147064 /* 768d62bc4baSyz147064 * see whether this link is a removed physical link. 769d62bc4baSyz147064 */ 770d62bc4baSyz147064 if ((class != DATALINK_CLASS_PHYS) || !(flags & DLADM_OPT_PERSIST) || 771d62bc4baSyz147064 (flags & DLADM_OPT_ACTIVE)) { 772d62bc4baSyz147064 status = DLADM_STATUS_BADARG; 773d62bc4baSyz147064 goto done; 774d62bc4baSyz147064 } 775d62bc4baSyz147064 776d62bc4baSyz147064 if (media == DL_ETHER) { 777d62bc4baSyz147064 del_arg.linkid = linkid; 7784ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(i_dladm_aggr_link_del, handle, 7794ac67f02SAnurag S. Maskey &del_arg, DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, 780d62bc4baSyz147064 DLADM_OPT_PERSIST); 7814ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(i_dladm_vlan_link_del, handle, 7824ac67f02SAnurag S. Maskey &del_arg, DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, 783d62bc4baSyz147064 DLADM_OPT_PERSIST); 7841cfa752fSRamaswamy Tummala } else if (media == DL_IB) { 7851cfa752fSRamaswamy Tummala del_arg.linkid = linkid; 7861cfa752fSRamaswamy Tummala (void) dladm_walk_datalink_id(i_dladm_part_link_del, handle, 7871cfa752fSRamaswamy Tummala &del_arg, DATALINK_CLASS_PART, DL_IB, DLADM_OPT_PERSIST); 788d62bc4baSyz147064 } 789d62bc4baSyz147064 7904ac67f02SAnurag S. Maskey (void) dladm_remove_conf(handle, linkid); 7912b24ab6bSSebastien Roy (void) dladm_destroy_datalink_id(handle, linkid, DLADM_OPT_PERSIST); 792d62bc4baSyz147064 done: 793d62bc4baSyz147064 del_phys_arg->rval = status; 794d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 795d62bc4baSyz147064 } 796d62bc4baSyz147064 797d62bc4baSyz147064 dladm_status_t 7984ac67f02SAnurag S. Maskey dladm_phys_delete(dladm_handle_t handle, datalink_id_t linkid) 799d62bc4baSyz147064 { 800d62bc4baSyz147064 del_phys_arg_t arg = {DLADM_STATUS_OK}; 801d62bc4baSyz147064 802d62bc4baSyz147064 if (linkid == DATALINK_ALL_LINKID) { 8034ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(i_dladm_phys_delete, handle, &arg, 804d62bc4baSyz147064 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, 805d62bc4baSyz147064 DLADM_OPT_PERSIST); 806d62bc4baSyz147064 return (DLADM_STATUS_OK); 807d62bc4baSyz147064 } else { 8084ac67f02SAnurag S. Maskey (void) i_dladm_phys_delete(handle, linkid, &arg); 809d62bc4baSyz147064 return (arg.rval); 810d62bc4baSyz147064 } 811d62bc4baSyz147064 } 812d62bc4baSyz147064 813d62bc4baSyz147064 dladm_status_t 8144ac67f02SAnurag S. Maskey dladm_phys_info(dladm_handle_t handle, datalink_id_t linkid, 8154ac67f02SAnurag S. Maskey dladm_phys_attr_t *dpap, uint32_t flags) 816d62bc4baSyz147064 { 817d62bc4baSyz147064 dladm_status_t status; 818d62bc4baSyz147064 819d62bc4baSyz147064 assert(flags == DLADM_OPT_ACTIVE || flags == DLADM_OPT_PERSIST); 820d62bc4baSyz147064 821d62bc4baSyz147064 switch (flags) { 822d62bc4baSyz147064 case DLADM_OPT_PERSIST: { 823d62bc4baSyz147064 dladm_conf_t conf; 824d62bc4baSyz147064 825*32715170SCathy Zhou status = dladm_getsnap_conf(handle, linkid, &conf); 826d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 827d62bc4baSyz147064 return (status); 828d62bc4baSyz147064 8294ac67f02SAnurag S. Maskey status = dladm_get_conf_field(handle, conf, FDEVNAME, 8304ac67f02SAnurag S. Maskey dpap->dp_dev, MAXLINKNAMELEN); 8314ac67f02SAnurag S. Maskey dladm_destroy_conf(handle, conf); 832d62bc4baSyz147064 return (status); 833d62bc4baSyz147064 } 834d62bc4baSyz147064 case DLADM_OPT_ACTIVE: { 835d62bc4baSyz147064 dld_ioc_phys_attr_t dip; 836d62bc4baSyz147064 837d62bc4baSyz147064 dip.dip_linkid = linkid; 8384ac67f02SAnurag S. Maskey if (ioctl(dladm_dld_fd(handle), DLDIOC_PHYS_ATTR, &dip) < 0) { 839d62bc4baSyz147064 status = dladm_errno2status(errno); 840d62bc4baSyz147064 return (status); 841d62bc4baSyz147064 } 842d62bc4baSyz147064 dpap->dp_novanity = dip.dip_novanity; 843d62bc4baSyz147064 (void) strlcpy(dpap->dp_dev, dip.dip_dev, MAXLINKNAMELEN); 844d62bc4baSyz147064 return (DLADM_STATUS_OK); 845d62bc4baSyz147064 } 846d62bc4baSyz147064 default: 847d62bc4baSyz147064 return (DLADM_STATUS_BADARG); 848d62bc4baSyz147064 } 849d62bc4baSyz147064 } 850d62bc4baSyz147064 851d62bc4baSyz147064 typedef struct i_walk_dev_state_s { 852d62bc4baSyz147064 const char *devname; 853d62bc4baSyz147064 datalink_id_t linkid; 854d62bc4baSyz147064 boolean_t found; 855d62bc4baSyz147064 } i_walk_dev_state_t; 856d62bc4baSyz147064 857d62bc4baSyz147064 int 8584ac67f02SAnurag S. Maskey i_dladm_walk_dev2linkid(dladm_handle_t handle, datalink_id_t linkid, void *arg) 859d62bc4baSyz147064 { 860d62bc4baSyz147064 dladm_phys_attr_t dpa; 861d62bc4baSyz147064 dladm_status_t status; 862d62bc4baSyz147064 i_walk_dev_state_t *statep = arg; 863d62bc4baSyz147064 8644ac67f02SAnurag S. Maskey status = dladm_phys_info(handle, linkid, &dpa, DLADM_OPT_PERSIST); 865d62bc4baSyz147064 if ((status == DLADM_STATUS_OK) && 866d62bc4baSyz147064 (strcmp(statep->devname, dpa.dp_dev) == 0)) { 867d62bc4baSyz147064 statep->found = B_TRUE; 868d62bc4baSyz147064 statep->linkid = linkid; 869d62bc4baSyz147064 return (DLADM_WALK_TERMINATE); 870d62bc4baSyz147064 } 871d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 872d62bc4baSyz147064 } 873d62bc4baSyz147064 874d62bc4baSyz147064 /* 875d62bc4baSyz147064 * Get the linkid from the physical device name. 876d62bc4baSyz147064 */ 877d62bc4baSyz147064 dladm_status_t 8784ac67f02SAnurag S. Maskey dladm_dev2linkid(dladm_handle_t handle, const char *devname, 8794ac67f02SAnurag S. Maskey datalink_id_t *linkidp) 880d62bc4baSyz147064 { 881d62bc4baSyz147064 i_walk_dev_state_t state; 882d62bc4baSyz147064 883d62bc4baSyz147064 state.found = B_FALSE; 884d62bc4baSyz147064 state.devname = devname; 885d62bc4baSyz147064 8864ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(i_dladm_walk_dev2linkid, handle, &state, 887d62bc4baSyz147064 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 888d62bc4baSyz147064 if (state.found == B_TRUE) { 889d62bc4baSyz147064 *linkidp = state.linkid; 890d62bc4baSyz147064 return (DLADM_STATUS_OK); 891d62bc4baSyz147064 } else { 892d62bc4baSyz147064 return (dladm_errno2status(ENOENT)); 893d62bc4baSyz147064 } 894d62bc4baSyz147064 } 895d62bc4baSyz147064 896d62bc4baSyz147064 static int 897d62bc4baSyz147064 parse_devname(const char *devname, char *driver, uint_t *ppa, size_t maxlen) 898d62bc4baSyz147064 { 899d62bc4baSyz147064 char *cp, *tp; 900d62bc4baSyz147064 int len; 901d62bc4baSyz147064 902d62bc4baSyz147064 /* 903d62bc4baSyz147064 * device name length must not be 0, and it must end with digit. 904d62bc4baSyz147064 */ 905d62bc4baSyz147064 if (((len = strlen(devname)) == 0) || !isdigit(devname[len - 1])) 906d62bc4baSyz147064 return (EINVAL); 907d62bc4baSyz147064 908d62bc4baSyz147064 (void) strlcpy(driver, devname, maxlen); 909d62bc4baSyz147064 cp = (char *)&driver[len - 1]; 910d62bc4baSyz147064 911d62bc4baSyz147064 for (tp = cp; isdigit(*tp); tp--) { 912d62bc4baSyz147064 if (tp <= driver) 913d62bc4baSyz147064 return (EINVAL); 914d62bc4baSyz147064 } 915d62bc4baSyz147064 916d62bc4baSyz147064 *ppa = atoi(tp + 1); 917d62bc4baSyz147064 *(tp + 1) = '\0'; 918d62bc4baSyz147064 return (0); 919d62bc4baSyz147064 } 920d62bc4baSyz147064 921d62bc4baSyz147064 dladm_status_t 9224ac67f02SAnurag S. Maskey dladm_linkid2legacyname(dladm_handle_t handle, datalink_id_t linkid, char *dev, 9234ac67f02SAnurag S. Maskey size_t len) 924d62bc4baSyz147064 { 925d62bc4baSyz147064 char devname[MAXLINKNAMELEN]; 926d62bc4baSyz147064 uint16_t vid = VLAN_ID_NONE; 927d62bc4baSyz147064 datalink_class_t class; 928d62bc4baSyz147064 dladm_status_t status; 929d62bc4baSyz147064 9304ac67f02SAnurag S. Maskey status = dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, 9314ac67f02SAnurag S. Maskey NULL, 0); 932d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 933d62bc4baSyz147064 goto done; 934d62bc4baSyz147064 935d62bc4baSyz147064 /* 936d62bc4baSyz147064 * If this is a VLAN, we must first determine the class and linkid of 937d62bc4baSyz147064 * the link the VLAN has been created over. 938d62bc4baSyz147064 */ 939d62bc4baSyz147064 if (class == DATALINK_CLASS_VLAN) { 940d62bc4baSyz147064 dladm_vlan_attr_t dva; 941d62bc4baSyz147064 9424ac67f02SAnurag S. Maskey status = dladm_vlan_info(handle, linkid, &dva, 9434ac67f02SAnurag S. Maskey DLADM_OPT_ACTIVE); 944d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 945d62bc4baSyz147064 goto done; 946d62bc4baSyz147064 linkid = dva.dv_linkid; 947d62bc4baSyz147064 vid = dva.dv_vid; 948d62bc4baSyz147064 9494ac67f02SAnurag S. Maskey if ((status = dladm_datalink_id2info(handle, linkid, NULL, 9504ac67f02SAnurag S. Maskey &class, NULL, NULL, 0)) != DLADM_STATUS_OK) { 951d62bc4baSyz147064 goto done; 952d62bc4baSyz147064 } 953d62bc4baSyz147064 } 954d62bc4baSyz147064 955d62bc4baSyz147064 switch (class) { 956d62bc4baSyz147064 case DATALINK_CLASS_AGGR: { 957d62bc4baSyz147064 dladm_aggr_grp_attr_t dga; 958d62bc4baSyz147064 9594ac67f02SAnurag S. Maskey status = dladm_aggr_info(handle, linkid, &dga, 9604ac67f02SAnurag S. Maskey DLADM_OPT_ACTIVE); 961d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 962d62bc4baSyz147064 goto done; 963d62bc4baSyz147064 964d62bc4baSyz147064 if (dga.lg_key == 0) { 965d62bc4baSyz147064 /* 966d62bc4baSyz147064 * If the key was not specified when the aggregation 967d62bc4baSyz147064 * is created, we cannot guess its /dev node name. 968d62bc4baSyz147064 */ 969d62bc4baSyz147064 status = DLADM_STATUS_BADARG; 970d62bc4baSyz147064 goto done; 971d62bc4baSyz147064 } 972d62bc4baSyz147064 (void) snprintf(devname, MAXLINKNAMELEN, "aggr%d", dga.lg_key); 973d62bc4baSyz147064 break; 974d62bc4baSyz147064 } 975d62bc4baSyz147064 case DATALINK_CLASS_PHYS: { 976d62bc4baSyz147064 dladm_phys_attr_t dpa; 977d62bc4baSyz147064 9784ac67f02SAnurag S. Maskey status = dladm_phys_info(handle, linkid, &dpa, 9794ac67f02SAnurag S. Maskey DLADM_OPT_PERSIST); 980d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 981d62bc4baSyz147064 goto done; 982d62bc4baSyz147064 983d62bc4baSyz147064 (void) strlcpy(devname, dpa.dp_dev, MAXLINKNAMELEN); 984d62bc4baSyz147064 break; 985d62bc4baSyz147064 } 986d62bc4baSyz147064 default: 987d62bc4baSyz147064 status = DLADM_STATUS_BADARG; 988d62bc4baSyz147064 goto done; 989d62bc4baSyz147064 } 990d62bc4baSyz147064 991d62bc4baSyz147064 if (vid != VLAN_ID_NONE) { 992d62bc4baSyz147064 char drv[MAXNAMELEN]; 993d62bc4baSyz147064 uint_t ppa; 994d62bc4baSyz147064 995d62bc4baSyz147064 if (parse_devname(devname, drv, &ppa, MAXNAMELEN) != 0) { 996d62bc4baSyz147064 status = DLADM_STATUS_BADARG; 997d62bc4baSyz147064 goto done; 998d62bc4baSyz147064 } 999d62bc4baSyz147064 if (snprintf(dev, len, "%s%d", drv, vid * 1000 + ppa) >= len) 1000d62bc4baSyz147064 status = DLADM_STATUS_TOOSMALL; 1001d62bc4baSyz147064 } else { 1002d62bc4baSyz147064 if (strlcpy(dev, devname, len) >= len) 1003d62bc4baSyz147064 status = DLADM_STATUS_TOOSMALL; 1004d62bc4baSyz147064 } 1005d62bc4baSyz147064 1006d62bc4baSyz147064 done: 1007d62bc4baSyz147064 return (status); 1008f595a68aSyz147064 } 1009e7801d59Ssowmini 1010e7801d59Ssowmini dladm_status_t 1011e7801d59Ssowmini dladm_parselink(const char *dev, char *provider, uint_t *ppa) 1012e7801d59Ssowmini { 1013e7801d59Ssowmini ifspec_t ifsp; 1014e7801d59Ssowmini 1015e7801d59Ssowmini if (dev == NULL || !ifparse_ifspec(dev, &ifsp)) 1016e7801d59Ssowmini return (DLADM_STATUS_LINKINVAL); 1017e7801d59Ssowmini 1018e7801d59Ssowmini if (provider != NULL) 1019e7801d59Ssowmini (void) strlcpy(provider, ifsp.ifsp_devnm, DLPI_LINKNAME_MAX); 1020e7801d59Ssowmini 1021e7801d59Ssowmini if (ppa != NULL) 1022e7801d59Ssowmini *ppa = ifsp.ifsp_ppa; 1023e7801d59Ssowmini 1024e7801d59Ssowmini return (DLADM_STATUS_OK); 1025e7801d59Ssowmini } 1026