13871Syz147064 /* 23871Syz147064 * CDDL HEADER START 33871Syz147064 * 43871Syz147064 * The contents of this file are subject to the terms of the 53871Syz147064 * Common Development and Distribution License (the "License"). 63871Syz147064 * You may not use this file except in compliance with the License. 73871Syz147064 * 83871Syz147064 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93871Syz147064 * or http://www.opensolaris.org/os/licensing. 103871Syz147064 * See the License for the specific language governing permissions 113871Syz147064 * and limitations under the License. 123871Syz147064 * 133871Syz147064 * When distributing Covered Code, include this CDDL HEADER in each 143871Syz147064 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153871Syz147064 * If applicable, add the following below this CDDL HEADER, with the 163871Syz147064 * fields enclosed by brackets "[]" replaced with your own identifying 173871Syz147064 * information: Portions Copyright [yyyy] [name of copyright owner] 183871Syz147064 * 193871Syz147064 * CDDL HEADER END 203871Syz147064 */ 213871Syz147064 /* 225895Syz147064 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 233871Syz147064 * Use is subject to license terms. 243871Syz147064 */ 253871Syz147064 263871Syz147064 #include <sys/types.h> 273871Syz147064 #include <unistd.h> 283871Syz147064 #include <errno.h> 293871Syz147064 #include <fcntl.h> 305895Syz147064 #include <assert.h> 315895Syz147064 #include <ctype.h> 323871Syz147064 #include <strings.h> 333871Syz147064 #include <sys/stat.h> 343871Syz147064 #include <sys/dld.h> 355895Syz147064 #include <sys/vlan.h> 367342SAruna.Ramakrishna@Sun.COM #include <zone.h> 375895Syz147064 #include <librcm.h> 383871Syz147064 #include <libdlpi.h> 393871Syz147064 #include <libdevinfo.h> 405895Syz147064 #include <libdlaggr.h> 415895Syz147064 #include <libdlvlan.h> 423871Syz147064 #include <libdllink.h> 435895Syz147064 #include <libdlmgmt.h> 443871Syz147064 #include <libdladm_impl.h> 455903Ssowmini #include <libinetutil.h> 463871Syz147064 473871Syz147064 /* 483871Syz147064 * Return the attributes of the specified datalink from the DLD driver. 493871Syz147064 */ 505895Syz147064 static dladm_status_t 51*8453SAnurag.Maskey@Sun.COM i_dladm_info(dladm_handle_t handle, const datalink_id_t linkid, 52*8453SAnurag.Maskey@Sun.COM dladm_attr_t *dap) 533871Syz147064 { 543871Syz147064 dld_ioc_attr_t dia; 553871Syz147064 565895Syz147064 dia.dia_linkid = linkid; 573871Syz147064 58*8453SAnurag.Maskey@Sun.COM if (ioctl(dladm_dld_fd(handle), DLDIOC_ATTR, &dia) < 0) 595895Syz147064 return (dladm_errno2status(errno)); 603871Syz147064 613871Syz147064 dap->da_max_sdu = dia.dia_max_sdu; 623871Syz147064 635895Syz147064 return (DLADM_STATUS_OK); 643871Syz147064 } 653871Syz147064 668275SEric Cheng static dladm_status_t 67*8453SAnurag.Maskey@Sun.COM dladm_usagelog(dladm_handle_t handle, dladm_logtype_t type, 68*8453SAnurag.Maskey@Sun.COM dld_ioc_usagelog_t *log_info) 698275SEric Cheng { 708275SEric Cheng if (type == DLADM_LOGTYPE_FLOW) 718275SEric Cheng log_info->ul_type = MAC_LOGTYPE_FLOW; 728275SEric Cheng else 738275SEric Cheng log_info->ul_type = MAC_LOGTYPE_LINK; 748275SEric Cheng 75*8453SAnurag.Maskey@Sun.COM if (ioctl(dladm_dld_fd(handle), DLDIOC_USAGELOG, log_info) < 0) 768275SEric Cheng return (DLADM_STATUS_IOERR); 77*8453SAnurag.Maskey@Sun.COM 788275SEric Cheng return (DLADM_STATUS_OK); 798275SEric Cheng } 808275SEric Cheng 818275SEric Cheng dladm_status_t 82*8453SAnurag.Maskey@Sun.COM dladm_start_usagelog(dladm_handle_t handle, dladm_logtype_t type, 83*8453SAnurag.Maskey@Sun.COM uint_t interval) 848275SEric Cheng { 858275SEric Cheng dld_ioc_usagelog_t log_info; 868275SEric Cheng 878275SEric Cheng log_info.ul_onoff = B_TRUE; 888275SEric Cheng log_info.ul_interval = interval; 898275SEric Cheng 90*8453SAnurag.Maskey@Sun.COM return (dladm_usagelog(handle, type, &log_info)); 918275SEric Cheng } 928275SEric Cheng 938275SEric Cheng dladm_status_t 94*8453SAnurag.Maskey@Sun.COM dladm_stop_usagelog(dladm_handle_t handle, dladm_logtype_t type) 958275SEric Cheng { 968275SEric Cheng dld_ioc_usagelog_t log_info; 978275SEric Cheng 988275SEric Cheng log_info.ul_onoff = B_FALSE; 998275SEric Cheng log_info.ul_interval = 0; 1008275SEric Cheng 101*8453SAnurag.Maskey@Sun.COM return (dladm_usagelog(handle, type, &log_info)); 1028275SEric Cheng } 1038275SEric Cheng 1045895Syz147064 struct i_dladm_walk_arg { 1055895Syz147064 dladm_walkcb_t *fn; 1065895Syz147064 void *arg; 1075895Syz147064 }; 1083871Syz147064 1095895Syz147064 static int 110*8453SAnurag.Maskey@Sun.COM i_dladm_walk(dladm_handle_t handle, datalink_id_t linkid, void *arg) 1115895Syz147064 { 1125895Syz147064 struct i_dladm_walk_arg *walk_arg = arg; 1135895Syz147064 char link[MAXLINKNAMELEN]; 1143871Syz147064 115*8453SAnurag.Maskey@Sun.COM if (dladm_datalink_id2info(handle, linkid, NULL, NULL, NULL, link, 1165895Syz147064 sizeof (link)) == DLADM_STATUS_OK) { 1175895Syz147064 return (walk_arg->fn(link, walk_arg->arg)); 1183871Syz147064 } 1193871Syz147064 1205895Syz147064 return (DLADM_WALK_CONTINUE); 1213871Syz147064 } 1223871Syz147064 1233871Syz147064 /* 1245895Syz147064 * Walk all datalinks. 1253871Syz147064 */ 1265895Syz147064 dladm_status_t 127*8453SAnurag.Maskey@Sun.COM dladm_walk(dladm_walkcb_t *fn, dladm_handle_t handle, void *arg, 128*8453SAnurag.Maskey@Sun.COM datalink_class_t class, datalink_media_t dmedia, uint32_t flags) 1293871Syz147064 { 1305895Syz147064 struct i_dladm_walk_arg walk_arg; 1313871Syz147064 1325895Syz147064 walk_arg.fn = fn; 1335895Syz147064 walk_arg.arg = arg; 134*8453SAnurag.Maskey@Sun.COM return (dladm_walk_datalink_id(i_dladm_walk, handle, &walk_arg, 1355895Syz147064 class, dmedia, flags)); 1363871Syz147064 } 1373871Syz147064 1388275SEric Cheng #define MAXGRPPERLINK 64 1398275SEric Cheng 1408275SEric Cheng int 141*8453SAnurag.Maskey@Sun.COM dladm_walk_hwgrp(dladm_handle_t handle, datalink_id_t linkid, void *arg, 1428275SEric Cheng boolean_t (*fn)(void *, dladm_hwgrp_attr_t *)) 1438275SEric Cheng { 144*8453SAnurag.Maskey@Sun.COM int bufsize, ret; 1458275SEric Cheng int nhwgrp = MAXGRPPERLINK; 1468275SEric Cheng dld_ioc_hwgrpget_t *iomp = NULL; 1478275SEric Cheng 1488275SEric Cheng bufsize = sizeof (dld_ioc_hwgrpget_t) + 1498275SEric Cheng nhwgrp * sizeof (dld_hwgrpinfo_t); 1508275SEric Cheng 1518275SEric Cheng if ((iomp = (dld_ioc_hwgrpget_t *)calloc(1, bufsize)) == NULL) 1528275SEric Cheng return (-1); 1538275SEric Cheng 1548275SEric Cheng iomp->dih_size = nhwgrp * sizeof (dld_hwgrpinfo_t); 1558275SEric Cheng iomp->dih_linkid = linkid; 1568275SEric Cheng 157*8453SAnurag.Maskey@Sun.COM ret = ioctl(dladm_dld_fd(handle), DLDIOC_GETHWGRP, iomp); 1588275SEric Cheng if (ret == 0) { 1598275SEric Cheng int i; 1608275SEric Cheng dld_hwgrpinfo_t *dhip; 1618275SEric Cheng dladm_hwgrp_attr_t attr; 1628275SEric Cheng 1638275SEric Cheng dhip = (dld_hwgrpinfo_t *)(iomp + 1); 1648275SEric Cheng for (i = 0; i < iomp->dih_n_groups; i++) { 1658275SEric Cheng bzero(&attr, sizeof (attr)); 1668275SEric Cheng 1678275SEric Cheng (void) strlcpy(attr.hg_link_name, 1688275SEric Cheng dhip->dhi_link_name, sizeof (attr.hg_link_name)); 1698275SEric Cheng attr.hg_grp_num = dhip->dhi_grp_num; 1708275SEric Cheng attr.hg_grp_type = dhip->dhi_grp_type; 1718275SEric Cheng attr.hg_n_rings = dhip->dhi_n_rings; 1728275SEric Cheng attr.hg_n_clnts = dhip->dhi_n_clnts; 1738275SEric Cheng (void) strlcpy(attr.hg_client_names, 1748275SEric Cheng dhip->dhi_clnts, sizeof (attr.hg_client_names)); 1758275SEric Cheng 1768275SEric Cheng if (!(*fn)(arg, &attr)) 1778275SEric Cheng break; 1788275SEric Cheng dhip++; 1798275SEric Cheng } 1808275SEric Cheng } 1818275SEric Cheng free(iomp); 1828275SEric Cheng return (ret); 1838275SEric Cheng } 1848275SEric Cheng 1858275SEric Cheng /* 1868275SEric Cheng * Invoke the specified callback for each MAC address entry defined on 1878275SEric Cheng * the specified device. 1888275SEric Cheng */ 1898275SEric Cheng int 190*8453SAnurag.Maskey@Sun.COM dladm_walk_macaddr(dladm_handle_t handle, datalink_id_t linkid, void *arg, 1918275SEric Cheng boolean_t (*fn)(void *, dladm_macaddr_attr_t *)) 1928275SEric Cheng { 193*8453SAnurag.Maskey@Sun.COM int bufsize, ret; 1948275SEric Cheng int nmacaddr = 1024; 1958275SEric Cheng dld_ioc_macaddrget_t *iomp = NULL; 1968275SEric Cheng 1978275SEric Cheng bufsize = sizeof (dld_ioc_macaddrget_t) + 1988275SEric Cheng nmacaddr * sizeof (dld_macaddrinfo_t); 1998275SEric Cheng 2008275SEric Cheng if ((iomp = (dld_ioc_macaddrget_t *)calloc(1, bufsize)) == NULL) 2018275SEric Cheng return (-1); 2028275SEric Cheng 2038275SEric Cheng iomp->dig_size = nmacaddr * sizeof (dld_macaddrinfo_t); 2048275SEric Cheng iomp->dig_linkid = linkid; 2058275SEric Cheng 206*8453SAnurag.Maskey@Sun.COM ret = ioctl(dladm_dld_fd(handle), DLDIOC_MACADDRGET, iomp); 2078275SEric Cheng if (ret == 0) { 2088275SEric Cheng int i; 2098275SEric Cheng dld_macaddrinfo_t *dmip; 2108275SEric Cheng dladm_macaddr_attr_t attr; 2118275SEric Cheng 2128275SEric Cheng dmip = (dld_macaddrinfo_t *)(iomp + 1); 2138275SEric Cheng for (i = 0; i < iomp->dig_count; i++) { 2148275SEric Cheng bzero(&attr, sizeof (attr)); 2158275SEric Cheng 2168275SEric Cheng attr.ma_slot = dmip->dmi_slot; 2178275SEric Cheng attr.ma_flags = 0; 2188275SEric Cheng if (dmip->dmi_flags & DLDIOCMACADDR_USED) 2198275SEric Cheng attr.ma_flags |= DLADM_MACADDR_USED; 2208275SEric Cheng bcopy(dmip->dmi_addr, attr.ma_addr, 2218275SEric Cheng dmip->dmi_addrlen); 2228275SEric Cheng attr.ma_addrlen = dmip->dmi_addrlen; 2238275SEric Cheng (void) strlcpy(attr.ma_client_name, 2248275SEric Cheng dmip->dmi_client_name, MAXNAMELEN); 2258275SEric Cheng attr.ma_client_linkid = dmip->dma_client_linkid; 2268275SEric Cheng 2278275SEric Cheng if (!(*fn)(arg, &attr)) 2288275SEric Cheng break; 2298275SEric Cheng dmip++; 2308275SEric Cheng } 2318275SEric Cheng } 2328275SEric Cheng free(iomp); 2338275SEric Cheng return (ret); 2348275SEric Cheng } 2358275SEric Cheng 2363871Syz147064 /* 2375895Syz147064 * These routines are used by administration tools such as dladm(1M) to 2383871Syz147064 * iterate through the list of MAC interfaces 2393871Syz147064 */ 2403871Syz147064 2413871Syz147064 typedef struct dladm_mac_dev { 2423871Syz147064 char dm_name[MAXNAMELEN]; 2435895Syz147064 struct dladm_mac_dev *dm_next; 2443871Syz147064 } dladm_mac_dev_t; 2453871Syz147064 2463871Syz147064 typedef struct macadm_walk { 2475895Syz147064 dladm_mac_dev_t *dmd_dev_list; 2483871Syz147064 } dladm_mac_walk_t; 2493871Syz147064 2503871Syz147064 /* 2513871Syz147064 * Local callback invoked for each DDI_NT_NET node. 2523871Syz147064 */ 2533871Syz147064 /* ARGSUSED */ 2543871Syz147064 static int 2553871Syz147064 i_dladm_mac_walk(di_node_t node, di_minor_t minor, void *arg) 2563871Syz147064 { 2573871Syz147064 dladm_mac_walk_t *dmwp = arg; 2583871Syz147064 dladm_mac_dev_t *dmdp = dmwp->dmd_dev_list; 2593871Syz147064 dladm_mac_dev_t **last_dmdp = &dmwp->dmd_dev_list; 2603871Syz147064 char mac[MAXNAMELEN]; 2613871Syz147064 2623871Syz147064 (void) snprintf(mac, MAXNAMELEN, "%s%d", 2633871Syz147064 di_driver_name(node), di_instance(node)); 2643871Syz147064 2653871Syz147064 /* 2663871Syz147064 * Skip aggregations. 2673871Syz147064 */ 2683871Syz147064 if (strcmp("aggr", di_driver_name(node)) == 0) 2693871Syz147064 return (DI_WALK_CONTINUE); 2703871Syz147064 2715895Syz147064 /* 2725895Syz147064 * Skip softmacs. 2735895Syz147064 */ 2745895Syz147064 if (strcmp("softmac", di_driver_name(node)) == 0) 2755895Syz147064 return (DI_WALK_CONTINUE); 2765895Syz147064 2773871Syz147064 while (dmdp) { 2783871Syz147064 /* 2793871Syz147064 * Skip duplicates. 2803871Syz147064 */ 2813871Syz147064 if (strcmp(dmdp->dm_name, mac) == 0) 2823871Syz147064 return (DI_WALK_CONTINUE); 2833871Syz147064 2843871Syz147064 last_dmdp = &dmdp->dm_next; 2853871Syz147064 dmdp = dmdp->dm_next; 2863871Syz147064 } 2873871Syz147064 2883871Syz147064 if ((dmdp = malloc(sizeof (*dmdp))) == NULL) 2893871Syz147064 return (DI_WALK_CONTINUE); 2903871Syz147064 2913871Syz147064 (void) strlcpy(dmdp->dm_name, mac, MAXNAMELEN); 2923871Syz147064 dmdp->dm_next = NULL; 2933871Syz147064 *last_dmdp = dmdp; 2943871Syz147064 2953871Syz147064 return (DI_WALK_CONTINUE); 2963871Syz147064 } 2973871Syz147064 2983871Syz147064 /* 2995895Syz147064 * Invoke the specified callback for each DDI_NT_NET node. 3003871Syz147064 */ 3015895Syz147064 dladm_status_t 3025895Syz147064 dladm_mac_walk(int (*fn)(const char *, void *arg), void *arg) 3033871Syz147064 { 3043871Syz147064 di_node_t root; 3053871Syz147064 dladm_mac_walk_t dmw; 3063871Syz147064 dladm_mac_dev_t *dmdp, *next; 3075895Syz147064 boolean_t done = B_FALSE; 3083871Syz147064 3093871Syz147064 if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) 3105895Syz147064 return (dladm_errno2status(errno)); 3113871Syz147064 3123871Syz147064 dmw.dmd_dev_list = NULL; 3133871Syz147064 3143871Syz147064 (void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, &dmw, 3153871Syz147064 i_dladm_mac_walk); 3163871Syz147064 3173871Syz147064 di_fini(root); 3183871Syz147064 3193871Syz147064 dmdp = dmw.dmd_dev_list; 3203871Syz147064 for (dmdp = dmw.dmd_dev_list; dmdp != NULL; dmdp = next) { 3213871Syz147064 next = dmdp->dm_next; 3225895Syz147064 if (!done && 3235895Syz147064 ((*fn)(dmdp->dm_name, arg) == DLADM_WALK_TERMINATE)) { 3245895Syz147064 done = B_TRUE; 3255895Syz147064 } 3263871Syz147064 free(dmdp); 3273871Syz147064 } 3283871Syz147064 3295895Syz147064 return (DLADM_STATUS_OK); 3303871Syz147064 } 3313871Syz147064 3323871Syz147064 /* 3335895Syz147064 * Get the current attributes of the specified datalink. 3343871Syz147064 */ 3355895Syz147064 dladm_status_t 336*8453SAnurag.Maskey@Sun.COM dladm_info(dladm_handle_t handle, datalink_id_t linkid, dladm_attr_t *dap) 3373871Syz147064 { 338*8453SAnurag.Maskey@Sun.COM return (i_dladm_info(handle, linkid, dap)); 3393871Syz147064 } 3403871Syz147064 3413871Syz147064 const char * 3423871Syz147064 dladm_linkstate2str(link_state_t state, char *buf) 3433871Syz147064 { 3443871Syz147064 const char *s; 3453871Syz147064 3463871Syz147064 switch (state) { 3473871Syz147064 case LINK_STATE_UP: 3483871Syz147064 s = "up"; 3493871Syz147064 break; 3503871Syz147064 case LINK_STATE_DOWN: 3513871Syz147064 s = "down"; 3523871Syz147064 break; 3533871Syz147064 default: 3543871Syz147064 s = "unknown"; 3553871Syz147064 break; 3563871Syz147064 } 3573871Syz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 3583871Syz147064 return (buf); 3593871Syz147064 } 3603871Syz147064 3613871Syz147064 const char * 3623871Syz147064 dladm_linkduplex2str(link_duplex_t duplex, char *buf) 3633871Syz147064 { 3643871Syz147064 const char *s; 3653871Syz147064 3663871Syz147064 switch (duplex) { 3673871Syz147064 case LINK_DUPLEX_FULL: 3683871Syz147064 s = "full"; 3693871Syz147064 break; 3703871Syz147064 case LINK_DUPLEX_HALF: 3713871Syz147064 s = "half"; 3723871Syz147064 break; 3733871Syz147064 default: 3743871Syz147064 s = "unknown"; 3753871Syz147064 break; 3763871Syz147064 } 3773871Syz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 3783871Syz147064 return (buf); 3793871Syz147064 } 3803871Syz147064 3813871Syz147064 /* 3826233Syz147064 * Set zoneid of a given link. Note that this function takes a link name 3836233Syz147064 * argument instead of a linkid, because a data-link (and its linkid) could 3848275SEric Cheng * be created implicitly as the result of this function. 3855895Syz147064 */ 3865895Syz147064 dladm_status_t 387*8453SAnurag.Maskey@Sun.COM dladm_setzid(dladm_handle_t handle, const char *dlname, char *zone_name) 3885895Syz147064 { 3897342SAruna.Ramakrishna@Sun.COM datalink_id_t linkid; 3907342SAruna.Ramakrishna@Sun.COM dladm_status_t status = DLADM_STATUS_OK; 3915895Syz147064 3927342SAruna.Ramakrishna@Sun.COM /* If the link does not exist, it is a ppa-hacked vlan. */ 393*8453SAnurag.Maskey@Sun.COM status = dladm_name2info(handle, dlname, &linkid, NULL, NULL, NULL); 3948275SEric Cheng if (status != DLADM_STATUS_OK) 3958275SEric Cheng return (status); 3965895Syz147064 397*8453SAnurag.Maskey@Sun.COM status = dladm_set_linkprop(handle, linkid, "zone", &zone_name, 1, 3987342SAruna.Ramakrishna@Sun.COM DLADM_OPT_ACTIVE); 3995895Syz147064 4005895Syz147064 return (status); 4015895Syz147064 } 4025895Syz147064 4035895Syz147064 /* 4045895Syz147064 * Case 1: rename an existing link1 to a link2 that does not exist. 4055895Syz147064 * Result: <linkid1, link2> 4063871Syz147064 */ 4075895Syz147064 static dladm_status_t 408*8453SAnurag.Maskey@Sun.COM i_dladm_rename_link_c1(dladm_handle_t handle, datalink_id_t linkid1, 409*8453SAnurag.Maskey@Sun.COM const char *link1, const char *link2, uint32_t flags) 4105895Syz147064 { 4115895Syz147064 dld_ioc_rename_t dir; 4125895Syz147064 dladm_conf_t conf; 4135895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 4145895Syz147064 4155895Syz147064 /* 4165895Syz147064 * Link is currently available. Check to see whether anything is 4175895Syz147064 * holding this link to prevent a rename operation. 4185895Syz147064 */ 4195895Syz147064 if (flags & DLADM_OPT_ACTIVE) { 4205895Syz147064 dir.dir_linkid1 = linkid1; 4215895Syz147064 dir.dir_linkid2 = DATALINK_INVALID_LINKID; 4225895Syz147064 (void) strlcpy(dir.dir_link, link2, MAXLINKNAMELEN); 4235895Syz147064 424*8453SAnurag.Maskey@Sun.COM if (ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir) < 0) { 4255895Syz147064 status = dladm_errno2status(errno); 4265895Syz147064 return (status); 4275895Syz147064 } 4285895Syz147064 } 4295895Syz147064 430*8453SAnurag.Maskey@Sun.COM status = dladm_remap_datalink_id(handle, linkid1, link2); 4315895Syz147064 if (status != DLADM_STATUS_OK) 4325895Syz147064 goto done; 4335895Syz147064 4345895Syz147064 /* 4355895Syz147064 * Flush the current mapping to persistent configuration. 4365895Syz147064 */ 4375895Syz147064 if ((flags & DLADM_OPT_PERSIST) && 438*8453SAnurag.Maskey@Sun.COM (((status = dladm_read_conf(handle, linkid1, &conf)) != 439*8453SAnurag.Maskey@Sun.COM DLADM_STATUS_OK) || 440*8453SAnurag.Maskey@Sun.COM ((status = dladm_write_conf(handle, conf)) != DLADM_STATUS_OK))) { 441*8453SAnurag.Maskey@Sun.COM (void) dladm_remap_datalink_id(handle, linkid1, link1); 4425895Syz147064 } 4435895Syz147064 done: 4445895Syz147064 if (flags & DLADM_OPT_ACTIVE) { 4455895Syz147064 if (status != DLADM_STATUS_OK) { 4465895Syz147064 (void) strlcpy(dir.dir_link, link1, MAXLINKNAMELEN); 447*8453SAnurag.Maskey@Sun.COM (void) ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir); 4485895Syz147064 } 4495895Syz147064 } 4505895Syz147064 return (status); 4515895Syz147064 } 4525895Syz147064 4535895Syz147064 typedef struct link_hold_arg_s { 4545895Syz147064 datalink_id_t linkid; 4555895Syz147064 datalink_id_t holder; 4565895Syz147064 uint32_t flags; 4575895Syz147064 } link_hold_arg_t; 4585895Syz147064 4595895Syz147064 static int 460*8453SAnurag.Maskey@Sun.COM i_dladm_aggr_link_hold(dladm_handle_t handle, datalink_id_t aggrid, void *arg) 4615895Syz147064 { 4625895Syz147064 link_hold_arg_t *hold_arg = arg; 4635895Syz147064 dladm_aggr_grp_attr_t ginfo; 4645895Syz147064 dladm_status_t status; 4655895Syz147064 int i; 4665895Syz147064 467*8453SAnurag.Maskey@Sun.COM status = dladm_aggr_info(handle, aggrid, &ginfo, hold_arg->flags); 4685895Syz147064 if (status != DLADM_STATUS_OK) 4695895Syz147064 return (DLADM_WALK_CONTINUE); 4705895Syz147064 4715895Syz147064 for (i = 0; i < ginfo.lg_nports; i++) { 4725895Syz147064 if (ginfo.lg_ports[i].lp_linkid == hold_arg->linkid) { 4735895Syz147064 hold_arg->holder = aggrid; 4745895Syz147064 return (DLADM_WALK_TERMINATE); 4755895Syz147064 } 4765895Syz147064 } 4775895Syz147064 return (DLADM_WALK_CONTINUE); 4785895Syz147064 } 4795895Syz147064 4805895Syz147064 static int 481*8453SAnurag.Maskey@Sun.COM i_dladm_vlan_link_hold(dladm_handle_t handle, datalink_id_t vlanid, void *arg) 4825895Syz147064 { 4835895Syz147064 link_hold_arg_t *hold_arg = arg; 4845895Syz147064 dladm_vlan_attr_t vinfo; 4855895Syz147064 dladm_status_t status; 4865895Syz147064 487*8453SAnurag.Maskey@Sun.COM status = dladm_vlan_info(handle, vlanid, &vinfo, hold_arg->flags); 4885895Syz147064 if (status != DLADM_STATUS_OK) 4895895Syz147064 return (DLADM_WALK_CONTINUE); 4905895Syz147064 4915895Syz147064 if (vinfo.dv_linkid == hold_arg->linkid) { 4925895Syz147064 hold_arg->holder = vlanid; 4935895Syz147064 return (DLADM_WALK_TERMINATE); 4945895Syz147064 } 4955895Syz147064 return (DLADM_WALK_CONTINUE); 4965895Syz147064 } 4975895Syz147064 4985895Syz147064 /* 4995895Syz147064 * Case 2: rename an available physical link link1 to a REMOVED physical link 5005895Syz147064 * link2. As a result, link1 directly inherits all datalinks configured 5015895Syz147064 * over link2 (linkid2). 5025895Syz147064 * Result: <linkid2, link2, link1_phymaj, link1_phyinst, link1_devname, 5035895Syz147064 * link2_other_attr> 5045895Syz147064 */ 5055895Syz147064 static dladm_status_t 506*8453SAnurag.Maskey@Sun.COM i_dladm_rename_link_c2(dladm_handle_t handle, datalink_id_t linkid1, 507*8453SAnurag.Maskey@Sun.COM datalink_id_t linkid2) 5083871Syz147064 { 5095895Syz147064 rcm_handle_t *rcm_hdl = NULL; 5105895Syz147064 nvlist_t *nvl = NULL; 5115895Syz147064 link_hold_arg_t arg; 5125895Syz147064 dld_ioc_rename_t dir; 5135895Syz147064 dladm_conf_t conf1, conf2; 5145895Syz147064 char devname[MAXLINKNAMELEN]; 5155895Syz147064 uint64_t phymaj, phyinst; 5165895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 5175895Syz147064 5185895Syz147064 /* 5195895Syz147064 * First check if linkid1 is associated with any persistent 5205895Syz147064 * aggregations or VLANs. If yes, return BUSY. 5215895Syz147064 */ 5225895Syz147064 arg.linkid = linkid1; 5235895Syz147064 arg.holder = DATALINK_INVALID_LINKID; 5245895Syz147064 arg.flags = DLADM_OPT_PERSIST; 525*8453SAnurag.Maskey@Sun.COM (void) dladm_walk_datalink_id(i_dladm_aggr_link_hold, handle, &arg, 5265895Syz147064 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 5275895Syz147064 if (arg.holder != DATALINK_INVALID_LINKID) 5285895Syz147064 return (DLADM_STATUS_LINKBUSY); 5295895Syz147064 5305895Syz147064 arg.flags = DLADM_OPT_PERSIST; 531*8453SAnurag.Maskey@Sun.COM (void) dladm_walk_datalink_id(i_dladm_vlan_link_hold, handle, &arg, 5325895Syz147064 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 5335895Syz147064 if (arg.holder != DATALINK_INVALID_LINKID) 5345895Syz147064 return (DLADM_STATUS_LINKBUSY); 5355895Syz147064 5365895Syz147064 /* 5375895Syz147064 * Send DLDIOC_RENAME to request to rename link1's linkid to 5385895Syz147064 * be linkid2. This will check whether link1 is used by any 5395895Syz147064 * aggregations or VLANs, or is held by any application. If yes, 5405895Syz147064 * return failure. 5415895Syz147064 */ 5425895Syz147064 dir.dir_linkid1 = linkid1; 5435895Syz147064 dir.dir_linkid2 = linkid2; 544*8453SAnurag.Maskey@Sun.COM if (ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir) < 0) 5455895Syz147064 status = dladm_errno2status(errno); 5465895Syz147064 5475895Syz147064 if (status != DLADM_STATUS_OK) { 5485895Syz147064 return (status); 5495895Syz147064 } 5505895Syz147064 5515895Syz147064 /* 5525895Syz147064 * Now change the phymaj, phyinst and devname associated with linkid1 5535895Syz147064 * to be associated with linkid2. Before doing that, the old active 5545895Syz147064 * linkprop of linkid1 should be deleted. 5555895Syz147064 */ 556*8453SAnurag.Maskey@Sun.COM (void) dladm_set_linkprop(handle, linkid1, NULL, NULL, 0, 557*8453SAnurag.Maskey@Sun.COM DLADM_OPT_ACTIVE); 5585895Syz147064 559*8453SAnurag.Maskey@Sun.COM if (((status = dladm_read_conf(handle, linkid1, &conf1)) != 560*8453SAnurag.Maskey@Sun.COM DLADM_STATUS_OK) || 561*8453SAnurag.Maskey@Sun.COM ((status = dladm_get_conf_field(handle, conf1, FDEVNAME, devname, 5625895Syz147064 MAXLINKNAMELEN)) != DLADM_STATUS_OK) || 563*8453SAnurag.Maskey@Sun.COM ((status = dladm_get_conf_field(handle, conf1, FPHYMAJ, &phymaj, 5645895Syz147064 sizeof (uint64_t))) != DLADM_STATUS_OK) || 565*8453SAnurag.Maskey@Sun.COM ((status = dladm_get_conf_field(handle, conf1, FPHYINST, &phyinst, 5665895Syz147064 sizeof (uint64_t))) != DLADM_STATUS_OK) || 567*8453SAnurag.Maskey@Sun.COM ((status = dladm_read_conf(handle, linkid2, &conf2)) != 568*8453SAnurag.Maskey@Sun.COM DLADM_STATUS_OK)) { 5695895Syz147064 dir.dir_linkid1 = linkid2; 5705895Syz147064 dir.dir_linkid2 = linkid1; 571*8453SAnurag.Maskey@Sun.COM (void) dladm_init_linkprop(handle, linkid1, B_FALSE); 572*8453SAnurag.Maskey@Sun.COM (void) ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir); 5735895Syz147064 return (status); 5745895Syz147064 } 5755895Syz147064 576*8453SAnurag.Maskey@Sun.COM dladm_destroy_conf(handle, conf1); 577*8453SAnurag.Maskey@Sun.COM (void) dladm_set_conf_field(handle, conf2, FDEVNAME, DLADM_TYPE_STR, 578*8453SAnurag.Maskey@Sun.COM devname); 579*8453SAnurag.Maskey@Sun.COM (void) dladm_set_conf_field(handle, conf2, FPHYMAJ, DLADM_TYPE_UINT64, 580*8453SAnurag.Maskey@Sun.COM &phymaj); 581*8453SAnurag.Maskey@Sun.COM (void) dladm_set_conf_field(handle, conf2, FPHYINST, 5825895Syz147064 DLADM_TYPE_UINT64, &phyinst); 583*8453SAnurag.Maskey@Sun.COM (void) dladm_write_conf(handle, conf2); 584*8453SAnurag.Maskey@Sun.COM dladm_destroy_conf(handle, conf2); 5855895Syz147064 5865895Syz147064 /* 5875895Syz147064 * Delete link1 and mark link2 up. 5885895Syz147064 */ 589*8453SAnurag.Maskey@Sun.COM (void) dladm_destroy_datalink_id(handle, linkid1, DLADM_OPT_ACTIVE | 5905895Syz147064 DLADM_OPT_PERSIST); 591*8453SAnurag.Maskey@Sun.COM (void) dladm_remove_conf(handle, linkid1); 592*8453SAnurag.Maskey@Sun.COM (void) dladm_up_datalink_id(handle, linkid2); 5935895Syz147064 5945895Syz147064 /* 5955895Syz147064 * Now generate the RCM_RESOURCE_LINK_NEW sysevent which can be 5965895Syz147064 * consumed by the RCM framework to restore all the datalink and 5975895Syz147064 * IP configuration. 5985895Syz147064 */ 5995895Syz147064 status = DLADM_STATUS_FAILED; 6005895Syz147064 if ((nvlist_alloc(&nvl, 0, 0) != 0) || 6015895Syz147064 (nvlist_add_uint64(nvl, RCM_NV_LINKID, linkid2) != 0)) { 6025895Syz147064 goto done; 6035895Syz147064 } 6045895Syz147064 6055895Syz147064 if (rcm_alloc_handle(NULL, 0, NULL, &rcm_hdl) != RCM_SUCCESS) 6065895Syz147064 goto done; 6075895Syz147064 6085895Syz147064 if (rcm_notify_event(rcm_hdl, RCM_RESOURCE_LINK_NEW, 0, nvl, NULL) == 6095895Syz147064 RCM_SUCCESS) { 6105895Syz147064 status = DLADM_STATUS_OK; 6115895Syz147064 } 6125895Syz147064 6135895Syz147064 done: 6145895Syz147064 if (rcm_hdl != NULL) 6155895Syz147064 (void) rcm_free_handle(rcm_hdl); 6165895Syz147064 if (nvl != NULL) 6175895Syz147064 nvlist_free(nvl); 6185895Syz147064 return (status); 6193871Syz147064 } 6203871Syz147064 6213871Syz147064 /* 6225895Syz147064 * case 3: rename a non-existent link to a REMOVED physical link. 6235895Syz147064 * Set the removed physical link's device name to link1, so that 6245895Syz147064 * when link1 attaches, it inherits all the link configuration of 6255895Syz147064 * the removed physical link. 6263871Syz147064 */ 6275895Syz147064 static dladm_status_t 628*8453SAnurag.Maskey@Sun.COM i_dladm_rename_link_c3(dladm_handle_t handle, const char *link1, 629*8453SAnurag.Maskey@Sun.COM datalink_id_t linkid2) 6305895Syz147064 { 6315895Syz147064 dladm_conf_t conf; 6325895Syz147064 dladm_status_t status; 6335895Syz147064 6345895Syz147064 if (!dladm_valid_linkname(link1)) 6355895Syz147064 return (DLADM_STATUS_LINKINVAL); 6365895Syz147064 637*8453SAnurag.Maskey@Sun.COM status = dladm_read_conf(handle, linkid2, &conf); 6385895Syz147064 if (status != DLADM_STATUS_OK) 6395895Syz147064 goto done; 6405895Syz147064 641*8453SAnurag.Maskey@Sun.COM if ((status = dladm_set_conf_field(handle, conf, FDEVNAME, 642*8453SAnurag.Maskey@Sun.COM DLADM_TYPE_STR, link1)) == DLADM_STATUS_OK) { 643*8453SAnurag.Maskey@Sun.COM status = dladm_write_conf(handle, conf); 6445895Syz147064 } 6455895Syz147064 646*8453SAnurag.Maskey@Sun.COM dladm_destroy_conf(handle, conf); 6475895Syz147064 6485895Syz147064 done: 6495895Syz147064 return (status); 6505895Syz147064 } 6515895Syz147064 6525895Syz147064 dladm_status_t 653*8453SAnurag.Maskey@Sun.COM dladm_rename_link(dladm_handle_t handle, const char *link1, const char *link2) 6545895Syz147064 { 6555895Syz147064 datalink_id_t linkid1 = DATALINK_INVALID_LINKID; 6565895Syz147064 datalink_id_t linkid2 = DATALINK_INVALID_LINKID; 6575895Syz147064 uint32_t flags1, flags2; 6585895Syz147064 datalink_class_t class1, class2; 6595895Syz147064 uint32_t media1, media2; 6605895Syz147064 boolean_t remphy2 = B_FALSE; 6615895Syz147064 dladm_status_t status; 6625895Syz147064 663*8453SAnurag.Maskey@Sun.COM (void) dladm_name2info(handle, link1, &linkid1, &flags1, &class1, 664*8453SAnurag.Maskey@Sun.COM &media1); 665*8453SAnurag.Maskey@Sun.COM if ((dladm_name2info(handle, link2, &linkid2, &flags2, &class2, 666*8453SAnurag.Maskey@Sun.COM &media2) == DLADM_STATUS_OK) && (class2 == DATALINK_CLASS_PHYS) && 6675895Syz147064 (flags2 == DLADM_OPT_PERSIST)) { 6685895Syz147064 /* 6695895Syz147064 * see whether link2 is a removed physical link. 6705895Syz147064 */ 6715895Syz147064 remphy2 = B_TRUE; 6725895Syz147064 } 6735895Syz147064 6745895Syz147064 if (linkid1 != DATALINK_INVALID_LINKID) { 6755895Syz147064 if (linkid2 == DATALINK_INVALID_LINKID) { 6765895Syz147064 /* 6775895Syz147064 * case 1: rename an existing link to a link that 6785895Syz147064 * does not exist. 6795895Syz147064 */ 680*8453SAnurag.Maskey@Sun.COM status = i_dladm_rename_link_c1(handle, linkid1, link1, 681*8453SAnurag.Maskey@Sun.COM link2, flags1); 6825895Syz147064 } else if (remphy2) { 6835895Syz147064 /* 6845895Syz147064 * case 2: rename an available link to a REMOVED 6855895Syz147064 * physical link. Return failure if link1 is not 6865895Syz147064 * an active physical link. 6875895Syz147064 */ 6885895Syz147064 if ((class1 != class2) || (media1 != media2) || 6895895Syz147064 !(flags1 & DLADM_OPT_ACTIVE)) { 6905895Syz147064 status = DLADM_STATUS_BADARG; 6915895Syz147064 } else { 692*8453SAnurag.Maskey@Sun.COM status = i_dladm_rename_link_c2(handle, linkid1, 6935895Syz147064 linkid2); 6945895Syz147064 } 6955895Syz147064 } else { 6965895Syz147064 status = DLADM_STATUS_EXIST; 6975895Syz147064 } 6985895Syz147064 } else if (remphy2) { 699*8453SAnurag.Maskey@Sun.COM status = i_dladm_rename_link_c3(handle, link1, linkid2); 7005895Syz147064 } else { 7015895Syz147064 status = DLADM_STATUS_NOTFOUND; 7025895Syz147064 } 7035895Syz147064 return (status); 7045895Syz147064 } 7055895Syz147064 7065895Syz147064 typedef struct consumer_del_phys_arg_s { 7075895Syz147064 datalink_id_t linkid; 7085895Syz147064 } consumer_del_phys_arg_t; 7095895Syz147064 7105895Syz147064 static int 711*8453SAnurag.Maskey@Sun.COM i_dladm_vlan_link_del(dladm_handle_t handle, datalink_id_t vlanid, void *arg) 7125895Syz147064 { 7135895Syz147064 consumer_del_phys_arg_t *del_arg = arg; 7145895Syz147064 dladm_vlan_attr_t vinfo; 7155895Syz147064 dladm_status_t status; 7165895Syz147064 717*8453SAnurag.Maskey@Sun.COM status = dladm_vlan_info(handle, vlanid, &vinfo, DLADM_OPT_PERSIST); 7185895Syz147064 if (status != DLADM_STATUS_OK) 7195895Syz147064 return (DLADM_WALK_CONTINUE); 7205895Syz147064 7215895Syz147064 if (vinfo.dv_linkid == del_arg->linkid) 722*8453SAnurag.Maskey@Sun.COM (void) dladm_vlan_delete(handle, vlanid, DLADM_OPT_PERSIST); 7235895Syz147064 return (DLADM_WALK_CONTINUE); 7245895Syz147064 } 7255895Syz147064 7265895Syz147064 static int 727*8453SAnurag.Maskey@Sun.COM i_dladm_aggr_link_del(dladm_handle_t handle, datalink_id_t aggrid, void *arg) 7285895Syz147064 { 7295895Syz147064 consumer_del_phys_arg_t *del_arg = arg; 7305895Syz147064 dladm_aggr_grp_attr_t ginfo; 7315895Syz147064 dladm_status_t status; 7325895Syz147064 dladm_aggr_port_attr_db_t port[1]; 7335895Syz147064 int i; 7345895Syz147064 735*8453SAnurag.Maskey@Sun.COM status = dladm_aggr_info(handle, aggrid, &ginfo, DLADM_OPT_PERSIST); 7365895Syz147064 if (status != DLADM_STATUS_OK) 7375895Syz147064 return (DLADM_WALK_CONTINUE); 7385895Syz147064 7395895Syz147064 for (i = 0; i < ginfo.lg_nports; i++) 7405895Syz147064 if (ginfo.lg_ports[i].lp_linkid == del_arg->linkid) 7415895Syz147064 break; 7425895Syz147064 7435895Syz147064 if (i != ginfo.lg_nports) { 7445895Syz147064 if (ginfo.lg_nports == 1 && i == 0) { 7455895Syz147064 consumer_del_phys_arg_t aggr_del_arg; 7465895Syz147064 7475895Syz147064 /* 7485895Syz147064 * First delete all the VLANs on this aggregation, then 7495895Syz147064 * delete the aggregation itself. 7505895Syz147064 */ 7515895Syz147064 aggr_del_arg.linkid = aggrid; 7525895Syz147064 (void) dladm_walk_datalink_id(i_dladm_vlan_link_del, 753*8453SAnurag.Maskey@Sun.COM handle, &aggr_del_arg, DATALINK_CLASS_VLAN, 7545895Syz147064 DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 755*8453SAnurag.Maskey@Sun.COM (void) dladm_aggr_delete(handle, aggrid, 756*8453SAnurag.Maskey@Sun.COM DLADM_OPT_PERSIST); 7575895Syz147064 } else { 7585895Syz147064 port[0].lp_linkid = del_arg->linkid; 759*8453SAnurag.Maskey@Sun.COM (void) dladm_aggr_remove(handle, aggrid, 1, port, 7605895Syz147064 DLADM_OPT_PERSIST); 7615895Syz147064 } 7625895Syz147064 } 7635895Syz147064 return (DLADM_WALK_CONTINUE); 7645895Syz147064 } 7655895Syz147064 7665895Syz147064 typedef struct del_phys_arg_s { 7675895Syz147064 dladm_status_t rval; 7685895Syz147064 } del_phys_arg_t; 7695895Syz147064 7705895Syz147064 static int 771*8453SAnurag.Maskey@Sun.COM i_dladm_phys_delete(dladm_handle_t handle, datalink_id_t linkid, void *arg) 7725895Syz147064 { 7735895Syz147064 uint32_t flags; 7745895Syz147064 datalink_class_t class; 7755895Syz147064 uint32_t media; 7765895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 7775895Syz147064 del_phys_arg_t *del_phys_arg = arg; 7785895Syz147064 consumer_del_phys_arg_t del_arg; 7795895Syz147064 780*8453SAnurag.Maskey@Sun.COM if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class, 7815895Syz147064 &media, NULL, 0)) != DLADM_STATUS_OK) { 7825895Syz147064 goto done; 7835895Syz147064 } 7845895Syz147064 7855895Syz147064 /* 7865895Syz147064 * see whether this link is a removed physical link. 7875895Syz147064 */ 7885895Syz147064 if ((class != DATALINK_CLASS_PHYS) || !(flags & DLADM_OPT_PERSIST) || 7895895Syz147064 (flags & DLADM_OPT_ACTIVE)) { 7905895Syz147064 status = DLADM_STATUS_BADARG; 7915895Syz147064 goto done; 7925895Syz147064 } 7935895Syz147064 7945895Syz147064 if (media == DL_ETHER) { 7955895Syz147064 del_arg.linkid = linkid; 796*8453SAnurag.Maskey@Sun.COM (void) dladm_walk_datalink_id(i_dladm_aggr_link_del, handle, 797*8453SAnurag.Maskey@Sun.COM &del_arg, DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, 7985895Syz147064 DLADM_OPT_PERSIST); 799*8453SAnurag.Maskey@Sun.COM (void) dladm_walk_datalink_id(i_dladm_vlan_link_del, handle, 800*8453SAnurag.Maskey@Sun.COM &del_arg, DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, 8015895Syz147064 DLADM_OPT_PERSIST); 8025895Syz147064 } 8035895Syz147064 804*8453SAnurag.Maskey@Sun.COM (void) dladm_destroy_datalink_id(handle, linkid, DLADM_OPT_PERSIST); 805*8453SAnurag.Maskey@Sun.COM (void) dladm_remove_conf(handle, linkid); 8065895Syz147064 8075895Syz147064 done: 8085895Syz147064 del_phys_arg->rval = status; 8095895Syz147064 return (DLADM_WALK_CONTINUE); 8105895Syz147064 } 8115895Syz147064 8125895Syz147064 dladm_status_t 813*8453SAnurag.Maskey@Sun.COM dladm_phys_delete(dladm_handle_t handle, datalink_id_t linkid) 8145895Syz147064 { 8155895Syz147064 del_phys_arg_t arg = {DLADM_STATUS_OK}; 8165895Syz147064 8175895Syz147064 if (linkid == DATALINK_ALL_LINKID) { 818*8453SAnurag.Maskey@Sun.COM (void) dladm_walk_datalink_id(i_dladm_phys_delete, handle, &arg, 8195895Syz147064 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, 8205895Syz147064 DLADM_OPT_PERSIST); 8215895Syz147064 return (DLADM_STATUS_OK); 8225895Syz147064 } else { 823*8453SAnurag.Maskey@Sun.COM (void) i_dladm_phys_delete(handle, linkid, &arg); 8245895Syz147064 return (arg.rval); 8255895Syz147064 } 8265895Syz147064 } 8275895Syz147064 8285895Syz147064 dladm_status_t 829*8453SAnurag.Maskey@Sun.COM dladm_phys_info(dladm_handle_t handle, datalink_id_t linkid, 830*8453SAnurag.Maskey@Sun.COM dladm_phys_attr_t *dpap, uint32_t flags) 8315895Syz147064 { 8325895Syz147064 dladm_status_t status; 8335895Syz147064 8345895Syz147064 assert(flags == DLADM_OPT_ACTIVE || flags == DLADM_OPT_PERSIST); 8355895Syz147064 8365895Syz147064 switch (flags) { 8375895Syz147064 case DLADM_OPT_PERSIST: { 8385895Syz147064 dladm_conf_t conf; 8395895Syz147064 840*8453SAnurag.Maskey@Sun.COM status = dladm_read_conf(handle, linkid, &conf); 8415895Syz147064 if (status != DLADM_STATUS_OK) 8425895Syz147064 return (status); 8435895Syz147064 844*8453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FDEVNAME, 845*8453SAnurag.Maskey@Sun.COM dpap->dp_dev, MAXLINKNAMELEN); 846*8453SAnurag.Maskey@Sun.COM dladm_destroy_conf(handle, conf); 8475895Syz147064 return (status); 8485895Syz147064 } 8495895Syz147064 case DLADM_OPT_ACTIVE: { 8505895Syz147064 dld_ioc_phys_attr_t dip; 8515895Syz147064 8525895Syz147064 dip.dip_linkid = linkid; 853*8453SAnurag.Maskey@Sun.COM if (ioctl(dladm_dld_fd(handle), DLDIOC_PHYS_ATTR, &dip) < 0) { 8545895Syz147064 status = dladm_errno2status(errno); 8555895Syz147064 return (status); 8565895Syz147064 } 8575895Syz147064 dpap->dp_novanity = dip.dip_novanity; 8585895Syz147064 (void) strlcpy(dpap->dp_dev, dip.dip_dev, MAXLINKNAMELEN); 8595895Syz147064 return (DLADM_STATUS_OK); 8605895Syz147064 } 8615895Syz147064 default: 8625895Syz147064 return (DLADM_STATUS_BADARG); 8635895Syz147064 } 8645895Syz147064 } 8655895Syz147064 8665895Syz147064 typedef struct i_walk_dev_state_s { 8675895Syz147064 const char *devname; 8685895Syz147064 datalink_id_t linkid; 8695895Syz147064 boolean_t found; 8705895Syz147064 } i_walk_dev_state_t; 8715895Syz147064 8723871Syz147064 int 873*8453SAnurag.Maskey@Sun.COM i_dladm_walk_dev2linkid(dladm_handle_t handle, datalink_id_t linkid, void *arg) 8745895Syz147064 { 8755895Syz147064 dladm_phys_attr_t dpa; 8765895Syz147064 dladm_status_t status; 8775895Syz147064 i_walk_dev_state_t *statep = arg; 8785895Syz147064 879*8453SAnurag.Maskey@Sun.COM status = dladm_phys_info(handle, linkid, &dpa, DLADM_OPT_PERSIST); 8805895Syz147064 if ((status == DLADM_STATUS_OK) && 8815895Syz147064 (strcmp(statep->devname, dpa.dp_dev) == 0)) { 8825895Syz147064 statep->found = B_TRUE; 8835895Syz147064 statep->linkid = linkid; 8845895Syz147064 return (DLADM_WALK_TERMINATE); 8855895Syz147064 } 8865895Syz147064 return (DLADM_WALK_CONTINUE); 8875895Syz147064 } 8885895Syz147064 8895895Syz147064 /* 8905895Syz147064 * Get the linkid from the physical device name. 8915895Syz147064 */ 8925895Syz147064 dladm_status_t 893*8453SAnurag.Maskey@Sun.COM dladm_dev2linkid(dladm_handle_t handle, const char *devname, 894*8453SAnurag.Maskey@Sun.COM datalink_id_t *linkidp) 8955895Syz147064 { 8965895Syz147064 i_walk_dev_state_t state; 8975895Syz147064 8985895Syz147064 state.found = B_FALSE; 8995895Syz147064 state.devname = devname; 9005895Syz147064 901*8453SAnurag.Maskey@Sun.COM (void) dladm_walk_datalink_id(i_dladm_walk_dev2linkid, handle, &state, 9025895Syz147064 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 9035895Syz147064 if (state.found == B_TRUE) { 9045895Syz147064 *linkidp = state.linkid; 9055895Syz147064 return (DLADM_STATUS_OK); 9065895Syz147064 } else { 9075895Syz147064 return (dladm_errno2status(ENOENT)); 9085895Syz147064 } 9095895Syz147064 } 9105895Syz147064 9115895Syz147064 static int 9125895Syz147064 parse_devname(const char *devname, char *driver, uint_t *ppa, size_t maxlen) 9135895Syz147064 { 9145895Syz147064 char *cp, *tp; 9155895Syz147064 int len; 9165895Syz147064 9175895Syz147064 /* 9185895Syz147064 * device name length must not be 0, and it must end with digit. 9195895Syz147064 */ 9205895Syz147064 if (((len = strlen(devname)) == 0) || !isdigit(devname[len - 1])) 9215895Syz147064 return (EINVAL); 9225895Syz147064 9235895Syz147064 (void) strlcpy(driver, devname, maxlen); 9245895Syz147064 cp = (char *)&driver[len - 1]; 9255895Syz147064 9265895Syz147064 for (tp = cp; isdigit(*tp); tp--) { 9275895Syz147064 if (tp <= driver) 9285895Syz147064 return (EINVAL); 9295895Syz147064 } 9305895Syz147064 9315895Syz147064 *ppa = atoi(tp + 1); 9325895Syz147064 *(tp + 1) = '\0'; 9335895Syz147064 return (0); 9345895Syz147064 } 9355895Syz147064 9365895Syz147064 dladm_status_t 937*8453SAnurag.Maskey@Sun.COM dladm_linkid2legacyname(dladm_handle_t handle, datalink_id_t linkid, char *dev, 938*8453SAnurag.Maskey@Sun.COM size_t len) 9393871Syz147064 { 9405895Syz147064 char devname[MAXLINKNAMELEN]; 9415895Syz147064 uint16_t vid = VLAN_ID_NONE; 9425895Syz147064 datalink_class_t class; 9435895Syz147064 dladm_status_t status; 9445895Syz147064 945*8453SAnurag.Maskey@Sun.COM status = dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, 946*8453SAnurag.Maskey@Sun.COM NULL, 0); 9475895Syz147064 if (status != DLADM_STATUS_OK) 9485895Syz147064 goto done; 9495895Syz147064 9505895Syz147064 /* 9515895Syz147064 * If this is a VLAN, we must first determine the class and linkid of 9525895Syz147064 * the link the VLAN has been created over. 9535895Syz147064 */ 9545895Syz147064 if (class == DATALINK_CLASS_VLAN) { 9555895Syz147064 dladm_vlan_attr_t dva; 9565895Syz147064 957*8453SAnurag.Maskey@Sun.COM status = dladm_vlan_info(handle, linkid, &dva, 958*8453SAnurag.Maskey@Sun.COM DLADM_OPT_ACTIVE); 9595895Syz147064 if (status != DLADM_STATUS_OK) 9605895Syz147064 goto done; 9615895Syz147064 linkid = dva.dv_linkid; 9625895Syz147064 vid = dva.dv_vid; 9635895Syz147064 964*8453SAnurag.Maskey@Sun.COM if ((status = dladm_datalink_id2info(handle, linkid, NULL, 965*8453SAnurag.Maskey@Sun.COM &class, NULL, NULL, 0)) != DLADM_STATUS_OK) { 9665895Syz147064 goto done; 9675895Syz147064 } 9685895Syz147064 } 9695895Syz147064 9705895Syz147064 switch (class) { 9715895Syz147064 case DATALINK_CLASS_AGGR: { 9725895Syz147064 dladm_aggr_grp_attr_t dga; 9735895Syz147064 974*8453SAnurag.Maskey@Sun.COM status = dladm_aggr_info(handle, linkid, &dga, 975*8453SAnurag.Maskey@Sun.COM DLADM_OPT_ACTIVE); 9765895Syz147064 if (status != DLADM_STATUS_OK) 9775895Syz147064 goto done; 9785895Syz147064 9795895Syz147064 if (dga.lg_key == 0) { 9805895Syz147064 /* 9815895Syz147064 * If the key was not specified when the aggregation 9825895Syz147064 * is created, we cannot guess its /dev node name. 9835895Syz147064 */ 9845895Syz147064 status = DLADM_STATUS_BADARG; 9855895Syz147064 goto done; 9865895Syz147064 } 9875895Syz147064 (void) snprintf(devname, MAXLINKNAMELEN, "aggr%d", dga.lg_key); 9885895Syz147064 break; 9895895Syz147064 } 9905895Syz147064 case DATALINK_CLASS_PHYS: { 9915895Syz147064 dladm_phys_attr_t dpa; 9925895Syz147064 993*8453SAnurag.Maskey@Sun.COM status = dladm_phys_info(handle, linkid, &dpa, 994*8453SAnurag.Maskey@Sun.COM DLADM_OPT_PERSIST); 9955895Syz147064 if (status != DLADM_STATUS_OK) 9965895Syz147064 goto done; 9975895Syz147064 9985895Syz147064 (void) strlcpy(devname, dpa.dp_dev, MAXLINKNAMELEN); 9995895Syz147064 break; 10005895Syz147064 } 10015895Syz147064 default: 10025895Syz147064 status = DLADM_STATUS_BADARG; 10035895Syz147064 goto done; 10045895Syz147064 } 10055895Syz147064 10065895Syz147064 if (vid != VLAN_ID_NONE) { 10075895Syz147064 char drv[MAXNAMELEN]; 10085895Syz147064 uint_t ppa; 10095895Syz147064 10105895Syz147064 if (parse_devname(devname, drv, &ppa, MAXNAMELEN) != 0) { 10115895Syz147064 status = DLADM_STATUS_BADARG; 10125895Syz147064 goto done; 10135895Syz147064 } 10145895Syz147064 if (snprintf(dev, len, "%s%d", drv, vid * 1000 + ppa) >= len) 10155895Syz147064 status = DLADM_STATUS_TOOSMALL; 10165895Syz147064 } else { 10175895Syz147064 if (strlcpy(dev, devname, len) >= len) 10185895Syz147064 status = DLADM_STATUS_TOOSMALL; 10195895Syz147064 } 10205895Syz147064 10215895Syz147064 done: 10225895Syz147064 return (status); 10233871Syz147064 } 10245903Ssowmini 10255903Ssowmini dladm_status_t 10265903Ssowmini dladm_parselink(const char *dev, char *provider, uint_t *ppa) 10275903Ssowmini { 10285903Ssowmini ifspec_t ifsp; 10295903Ssowmini 10305903Ssowmini if (dev == NULL || !ifparse_ifspec(dev, &ifsp)) 10315903Ssowmini return (DLADM_STATUS_LINKINVAL); 10325903Ssowmini 10335903Ssowmini if (provider != NULL) 10345903Ssowmini (void) strlcpy(provider, ifsp.ifsp_devnm, DLPI_LINKNAME_MAX); 10355903Ssowmini 10365903Ssowmini if (ppa != NULL) 10375903Ssowmini *ppa = ifsp.ifsp_ppa; 10385903Ssowmini 10395903Ssowmini return (DLADM_STATUS_OK); 10405903Ssowmini } 1041