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 /*
2212163SRamaswamy.Tummala@Sun.COM * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
233871Syz147064 */
243871Syz147064
253871Syz147064 #include <sys/types.h>
263871Syz147064 #include <unistd.h>
273871Syz147064 #include <errno.h>
283871Syz147064 #include <fcntl.h>
295895Syz147064 #include <assert.h>
305895Syz147064 #include <ctype.h>
313871Syz147064 #include <strings.h>
323871Syz147064 #include <sys/stat.h>
333871Syz147064 #include <sys/dld.h>
345895Syz147064 #include <sys/vlan.h>
357342SAruna.Ramakrishna@Sun.COM #include <zone.h>
365895Syz147064 #include <librcm.h>
373871Syz147064 #include <libdlpi.h>
383871Syz147064 #include <libdevinfo.h>
395895Syz147064 #include <libdlaggr.h>
405895Syz147064 #include <libdlvlan.h>
4111878SVenu.Iyer@Sun.COM #include <libdlvnic.h>
4212163SRamaswamy.Tummala@Sun.COM #include <libdlib.h>
433871Syz147064 #include <libdllink.h>
445895Syz147064 #include <libdlmgmt.h>
453871Syz147064 #include <libdladm_impl.h>
465903Ssowmini #include <libinetutil.h>
473871Syz147064
483871Syz147064 /*
493871Syz147064 * Return the attributes of the specified datalink from the DLD driver.
503871Syz147064 */
515895Syz147064 static dladm_status_t
i_dladm_info(dladm_handle_t handle,const datalink_id_t linkid,dladm_attr_t * dap)528453SAnurag.Maskey@Sun.COM i_dladm_info(dladm_handle_t handle, const datalink_id_t linkid,
538453SAnurag.Maskey@Sun.COM dladm_attr_t *dap)
543871Syz147064 {
553871Syz147064 dld_ioc_attr_t dia;
563871Syz147064
575895Syz147064 dia.dia_linkid = linkid;
583871Syz147064
598453SAnurag.Maskey@Sun.COM if (ioctl(dladm_dld_fd(handle), DLDIOC_ATTR, &dia) < 0)
605895Syz147064 return (dladm_errno2status(errno));
613871Syz147064
623871Syz147064 dap->da_max_sdu = dia.dia_max_sdu;
633871Syz147064
645895Syz147064 return (DLADM_STATUS_OK);
653871Syz147064 }
663871Syz147064
678275SEric Cheng static dladm_status_t
dladm_usagelog(dladm_handle_t handle,dladm_logtype_t type,dld_ioc_usagelog_t * log_info)688453SAnurag.Maskey@Sun.COM dladm_usagelog(dladm_handle_t handle, dladm_logtype_t type,
698453SAnurag.Maskey@Sun.COM dld_ioc_usagelog_t *log_info)
708275SEric Cheng {
718275SEric Cheng if (type == DLADM_LOGTYPE_FLOW)
728275SEric Cheng log_info->ul_type = MAC_LOGTYPE_FLOW;
738275SEric Cheng else
748275SEric Cheng log_info->ul_type = MAC_LOGTYPE_LINK;
758275SEric Cheng
768453SAnurag.Maskey@Sun.COM if (ioctl(dladm_dld_fd(handle), DLDIOC_USAGELOG, log_info) < 0)
778275SEric Cheng return (DLADM_STATUS_IOERR);
788453SAnurag.Maskey@Sun.COM
798275SEric Cheng return (DLADM_STATUS_OK);
808275SEric Cheng }
818275SEric Cheng
828275SEric Cheng dladm_status_t
dladm_start_usagelog(dladm_handle_t handle,dladm_logtype_t type,uint_t interval)838453SAnurag.Maskey@Sun.COM dladm_start_usagelog(dladm_handle_t handle, dladm_logtype_t type,
848453SAnurag.Maskey@Sun.COM uint_t interval)
858275SEric Cheng {
868275SEric Cheng dld_ioc_usagelog_t log_info;
878275SEric Cheng
888275SEric Cheng log_info.ul_onoff = B_TRUE;
898275SEric Cheng log_info.ul_interval = interval;
908275SEric Cheng
918453SAnurag.Maskey@Sun.COM return (dladm_usagelog(handle, type, &log_info));
928275SEric Cheng }
938275SEric Cheng
948275SEric Cheng dladm_status_t
dladm_stop_usagelog(dladm_handle_t handle,dladm_logtype_t type)958453SAnurag.Maskey@Sun.COM dladm_stop_usagelog(dladm_handle_t handle, dladm_logtype_t type)
968275SEric Cheng {
978275SEric Cheng dld_ioc_usagelog_t log_info;
988275SEric Cheng
998275SEric Cheng log_info.ul_onoff = B_FALSE;
1008275SEric Cheng log_info.ul_interval = 0;
1018275SEric Cheng
1028453SAnurag.Maskey@Sun.COM return (dladm_usagelog(handle, type, &log_info));
1038275SEric Cheng }
1048275SEric Cheng
1055895Syz147064 struct i_dladm_walk_arg {
1065895Syz147064 dladm_walkcb_t *fn;
1075895Syz147064 void *arg;
1085895Syz147064 };
1093871Syz147064
1105895Syz147064 static int
i_dladm_walk(dladm_handle_t handle,datalink_id_t linkid,void * arg)1118453SAnurag.Maskey@Sun.COM i_dladm_walk(dladm_handle_t handle, datalink_id_t linkid, void *arg)
1125895Syz147064 {
1135895Syz147064 struct i_dladm_walk_arg *walk_arg = arg;
1145895Syz147064 char link[MAXLINKNAMELEN];
1153871Syz147064
1168453SAnurag.Maskey@Sun.COM if (dladm_datalink_id2info(handle, linkid, NULL, NULL, NULL, link,
1175895Syz147064 sizeof (link)) == DLADM_STATUS_OK) {
1185895Syz147064 return (walk_arg->fn(link, walk_arg->arg));
1193871Syz147064 }
1203871Syz147064
1215895Syz147064 return (DLADM_WALK_CONTINUE);
1223871Syz147064 }
1233871Syz147064
1243871Syz147064 /*
1255895Syz147064 * Walk all datalinks.
1263871Syz147064 */
1275895Syz147064 dladm_status_t
dladm_walk(dladm_walkcb_t * fn,dladm_handle_t handle,void * arg,datalink_class_t class,datalink_media_t dmedia,uint32_t flags)1288453SAnurag.Maskey@Sun.COM dladm_walk(dladm_walkcb_t *fn, dladm_handle_t handle, void *arg,
1298453SAnurag.Maskey@Sun.COM datalink_class_t class, datalink_media_t dmedia, uint32_t flags)
1303871Syz147064 {
1315895Syz147064 struct i_dladm_walk_arg walk_arg;
1323871Syz147064
1335895Syz147064 walk_arg.fn = fn;
1345895Syz147064 walk_arg.arg = arg;
1358453SAnurag.Maskey@Sun.COM return (dladm_walk_datalink_id(i_dladm_walk, handle, &walk_arg,
1365895Syz147064 class, dmedia, flags));
1373871Syz147064 }
1383871Syz147064
1398275SEric Cheng #define MAXGRPPERLINK 64
1408275SEric Cheng
1418275SEric Cheng int
dladm_walk_hwgrp(dladm_handle_t handle,datalink_id_t linkid,void * arg,boolean_t (* fn)(void *,dladm_hwgrp_attr_t *))1428453SAnurag.Maskey@Sun.COM dladm_walk_hwgrp(dladm_handle_t handle, datalink_id_t linkid, void *arg,
1438275SEric Cheng boolean_t (*fn)(void *, dladm_hwgrp_attr_t *))
1448275SEric Cheng {
1458453SAnurag.Maskey@Sun.COM int bufsize, ret;
1468275SEric Cheng int nhwgrp = MAXGRPPERLINK;
1478275SEric Cheng dld_ioc_hwgrpget_t *iomp = NULL;
1488275SEric Cheng
1498275SEric Cheng bufsize = sizeof (dld_ioc_hwgrpget_t) +
1508275SEric Cheng nhwgrp * sizeof (dld_hwgrpinfo_t);
1518275SEric Cheng
1528275SEric Cheng if ((iomp = (dld_ioc_hwgrpget_t *)calloc(1, bufsize)) == NULL)
1538275SEric Cheng return (-1);
1548275SEric Cheng
1558275SEric Cheng iomp->dih_size = nhwgrp * sizeof (dld_hwgrpinfo_t);
1568275SEric Cheng iomp->dih_linkid = linkid;
1578275SEric Cheng
1588453SAnurag.Maskey@Sun.COM ret = ioctl(dladm_dld_fd(handle), DLDIOC_GETHWGRP, iomp);
1598275SEric Cheng if (ret == 0) {
16011878SVenu.Iyer@Sun.COM int i;
16111878SVenu.Iyer@Sun.COM int j;
16211878SVenu.Iyer@Sun.COM dld_hwgrpinfo_t *dhip;
16311878SVenu.Iyer@Sun.COM dladm_hwgrp_attr_t attr;
1648275SEric Cheng
1658275SEric Cheng dhip = (dld_hwgrpinfo_t *)(iomp + 1);
1668275SEric Cheng for (i = 0; i < iomp->dih_n_groups; i++) {
1678275SEric Cheng bzero(&attr, sizeof (attr));
1688275SEric Cheng
1698275SEric Cheng (void) strlcpy(attr.hg_link_name,
1708275SEric Cheng dhip->dhi_link_name, sizeof (attr.hg_link_name));
1718275SEric Cheng attr.hg_grp_num = dhip->dhi_grp_num;
1728275SEric Cheng attr.hg_grp_type = dhip->dhi_grp_type;
1738275SEric Cheng attr.hg_n_rings = dhip->dhi_n_rings;
17411878SVenu.Iyer@Sun.COM for (j = 0; j < dhip->dhi_n_rings; j++)
17511878SVenu.Iyer@Sun.COM attr.hg_rings[j] = dhip->dhi_rings[j];
17611878SVenu.Iyer@Sun.COM dladm_sort_index_list(attr.hg_rings, attr.hg_n_rings);
1778275SEric Cheng attr.hg_n_clnts = dhip->dhi_n_clnts;
1788275SEric Cheng (void) strlcpy(attr.hg_client_names,
1798275SEric Cheng dhip->dhi_clnts, sizeof (attr.hg_client_names));
1808275SEric Cheng
1818275SEric Cheng if (!(*fn)(arg, &attr))
1828275SEric Cheng break;
1838275SEric Cheng dhip++;
1848275SEric Cheng }
1858275SEric Cheng }
1868275SEric Cheng free(iomp);
1878275SEric Cheng return (ret);
1888275SEric Cheng }
1898275SEric Cheng
1908275SEric Cheng /*
1918275SEric Cheng * Invoke the specified callback for each MAC address entry defined on
1928275SEric Cheng * the specified device.
1938275SEric Cheng */
1948275SEric Cheng int
dladm_walk_macaddr(dladm_handle_t handle,datalink_id_t linkid,void * arg,boolean_t (* fn)(void *,dladm_macaddr_attr_t *))1958453SAnurag.Maskey@Sun.COM dladm_walk_macaddr(dladm_handle_t handle, datalink_id_t linkid, void *arg,
1968275SEric Cheng boolean_t (*fn)(void *, dladm_macaddr_attr_t *))
1978275SEric Cheng {
1988453SAnurag.Maskey@Sun.COM int bufsize, ret;
1998275SEric Cheng int nmacaddr = 1024;
2008275SEric Cheng dld_ioc_macaddrget_t *iomp = NULL;
2018275SEric Cheng
2028275SEric Cheng bufsize = sizeof (dld_ioc_macaddrget_t) +
2038275SEric Cheng nmacaddr * sizeof (dld_macaddrinfo_t);
2048275SEric Cheng
2058275SEric Cheng if ((iomp = (dld_ioc_macaddrget_t *)calloc(1, bufsize)) == NULL)
2068275SEric Cheng return (-1);
2078275SEric Cheng
2088275SEric Cheng iomp->dig_size = nmacaddr * sizeof (dld_macaddrinfo_t);
2098275SEric Cheng iomp->dig_linkid = linkid;
2108275SEric Cheng
2118453SAnurag.Maskey@Sun.COM ret = ioctl(dladm_dld_fd(handle), DLDIOC_MACADDRGET, iomp);
2128275SEric Cheng if (ret == 0) {
2138275SEric Cheng int i;
2148275SEric Cheng dld_macaddrinfo_t *dmip;
2158275SEric Cheng dladm_macaddr_attr_t attr;
2168275SEric Cheng
2178275SEric Cheng dmip = (dld_macaddrinfo_t *)(iomp + 1);
2188275SEric Cheng for (i = 0; i < iomp->dig_count; i++) {
2198275SEric Cheng bzero(&attr, sizeof (attr));
2208275SEric Cheng
2218275SEric Cheng attr.ma_slot = dmip->dmi_slot;
2228275SEric Cheng attr.ma_flags = 0;
2238275SEric Cheng if (dmip->dmi_flags & DLDIOCMACADDR_USED)
2248275SEric Cheng attr.ma_flags |= DLADM_MACADDR_USED;
2258275SEric Cheng bcopy(dmip->dmi_addr, attr.ma_addr,
2268275SEric Cheng dmip->dmi_addrlen);
2278275SEric Cheng attr.ma_addrlen = dmip->dmi_addrlen;
2288275SEric Cheng (void) strlcpy(attr.ma_client_name,
2298275SEric Cheng dmip->dmi_client_name, MAXNAMELEN);
2308275SEric Cheng attr.ma_client_linkid = dmip->dma_client_linkid;
2318275SEric Cheng
2328275SEric Cheng if (!(*fn)(arg, &attr))
2338275SEric Cheng break;
2348275SEric Cheng dmip++;
2358275SEric Cheng }
2368275SEric Cheng }
2378275SEric Cheng free(iomp);
2388275SEric Cheng return (ret);
2398275SEric Cheng }
2408275SEric Cheng
2413871Syz147064 /*
2425895Syz147064 * These routines are used by administration tools such as dladm(1M) to
2433871Syz147064 * iterate through the list of MAC interfaces
2443871Syz147064 */
2453871Syz147064
2463871Syz147064 typedef struct dladm_mac_dev {
2473871Syz147064 char dm_name[MAXNAMELEN];
2485895Syz147064 struct dladm_mac_dev *dm_next;
2493871Syz147064 } dladm_mac_dev_t;
2503871Syz147064
2513871Syz147064 typedef struct macadm_walk {
2525895Syz147064 dladm_mac_dev_t *dmd_dev_list;
2533871Syz147064 } dladm_mac_walk_t;
2543871Syz147064
2553871Syz147064 /*
2563871Syz147064 * Local callback invoked for each DDI_NT_NET node.
2573871Syz147064 */
2583871Syz147064 /* ARGSUSED */
2593871Syz147064 static int
i_dladm_mac_walk(di_node_t node,di_minor_t minor,void * arg)2603871Syz147064 i_dladm_mac_walk(di_node_t node, di_minor_t minor, void *arg)
2613871Syz147064 {
2623871Syz147064 dladm_mac_walk_t *dmwp = arg;
2633871Syz147064 dladm_mac_dev_t *dmdp = dmwp->dmd_dev_list;
2643871Syz147064 dladm_mac_dev_t **last_dmdp = &dmwp->dmd_dev_list;
2653871Syz147064 char mac[MAXNAMELEN];
2663871Syz147064
2673871Syz147064 (void) snprintf(mac, MAXNAMELEN, "%s%d",
2683871Syz147064 di_driver_name(node), di_instance(node));
2693871Syz147064
2703871Syz147064 /*
2713871Syz147064 * Skip aggregations.
2723871Syz147064 */
2733871Syz147064 if (strcmp("aggr", di_driver_name(node)) == 0)
2743871Syz147064 return (DI_WALK_CONTINUE);
2753871Syz147064
2765895Syz147064 /*
2775895Syz147064 * Skip softmacs.
2785895Syz147064 */
2795895Syz147064 if (strcmp("softmac", di_driver_name(node)) == 0)
2805895Syz147064 return (DI_WALK_CONTINUE);
2815895Syz147064
2823871Syz147064 while (dmdp) {
2833871Syz147064 /*
2843871Syz147064 * Skip duplicates.
2853871Syz147064 */
2863871Syz147064 if (strcmp(dmdp->dm_name, mac) == 0)
2873871Syz147064 return (DI_WALK_CONTINUE);
2883871Syz147064
2893871Syz147064 last_dmdp = &dmdp->dm_next;
2903871Syz147064 dmdp = dmdp->dm_next;
2913871Syz147064 }
2923871Syz147064
2933871Syz147064 if ((dmdp = malloc(sizeof (*dmdp))) == NULL)
2943871Syz147064 return (DI_WALK_CONTINUE);
2953871Syz147064
2963871Syz147064 (void) strlcpy(dmdp->dm_name, mac, MAXNAMELEN);
2973871Syz147064 dmdp->dm_next = NULL;
2983871Syz147064 *last_dmdp = dmdp;
2993871Syz147064
3003871Syz147064 return (DI_WALK_CONTINUE);
3013871Syz147064 }
3023871Syz147064
3033871Syz147064 /*
3045895Syz147064 * Invoke the specified callback for each DDI_NT_NET node.
3053871Syz147064 */
3065895Syz147064 dladm_status_t
dladm_mac_walk(int (* fn)(const char *,void * arg),void * arg)3075895Syz147064 dladm_mac_walk(int (*fn)(const char *, void *arg), void *arg)
3083871Syz147064 {
3093871Syz147064 di_node_t root;
3103871Syz147064 dladm_mac_walk_t dmw;
3113871Syz147064 dladm_mac_dev_t *dmdp, *next;
3125895Syz147064 boolean_t done = B_FALSE;
3133871Syz147064
3143871Syz147064 if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL)
3155895Syz147064 return (dladm_errno2status(errno));
3163871Syz147064
3173871Syz147064 dmw.dmd_dev_list = NULL;
3183871Syz147064
3193871Syz147064 (void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, &dmw,
3203871Syz147064 i_dladm_mac_walk);
3213871Syz147064
3223871Syz147064 di_fini(root);
3233871Syz147064
3243871Syz147064 dmdp = dmw.dmd_dev_list;
3253871Syz147064 for (dmdp = dmw.dmd_dev_list; dmdp != NULL; dmdp = next) {
3263871Syz147064 next = dmdp->dm_next;
3275895Syz147064 if (!done &&
3285895Syz147064 ((*fn)(dmdp->dm_name, arg) == DLADM_WALK_TERMINATE)) {
3295895Syz147064 done = B_TRUE;
3305895Syz147064 }
3313871Syz147064 free(dmdp);
3323871Syz147064 }
3333871Syz147064
3345895Syz147064 return (DLADM_STATUS_OK);
3353871Syz147064 }
3363871Syz147064
3373871Syz147064 /*
3385895Syz147064 * Get the current attributes of the specified datalink.
3393871Syz147064 */
3405895Syz147064 dladm_status_t
dladm_info(dladm_handle_t handle,datalink_id_t linkid,dladm_attr_t * dap)3418453SAnurag.Maskey@Sun.COM dladm_info(dladm_handle_t handle, datalink_id_t linkid, dladm_attr_t *dap)
3423871Syz147064 {
3438453SAnurag.Maskey@Sun.COM return (i_dladm_info(handle, linkid, dap));
3443871Syz147064 }
3453871Syz147064
3463871Syz147064 const char *
dladm_linkstate2str(link_state_t state,char * buf)3473871Syz147064 dladm_linkstate2str(link_state_t state, char *buf)
3483871Syz147064 {
3493871Syz147064 const char *s;
3503871Syz147064
3513871Syz147064 switch (state) {
3523871Syz147064 case LINK_STATE_UP:
3533871Syz147064 s = "up";
3543871Syz147064 break;
3553871Syz147064 case LINK_STATE_DOWN:
3563871Syz147064 s = "down";
3573871Syz147064 break;
3583871Syz147064 default:
3593871Syz147064 s = "unknown";
3603871Syz147064 break;
3613871Syz147064 }
3623871Syz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", s);
3633871Syz147064 return (buf);
3643871Syz147064 }
3653871Syz147064
3663871Syz147064 const char *
dladm_linkduplex2str(link_duplex_t duplex,char * buf)3673871Syz147064 dladm_linkduplex2str(link_duplex_t duplex, char *buf)
3683871Syz147064 {
3693871Syz147064 const char *s;
3703871Syz147064
3713871Syz147064 switch (duplex) {
3723871Syz147064 case LINK_DUPLEX_FULL:
3733871Syz147064 s = "full";
3743871Syz147064 break;
3753871Syz147064 case LINK_DUPLEX_HALF:
3763871Syz147064 s = "half";
3773871Syz147064 break;
3783871Syz147064 default:
3793871Syz147064 s = "unknown";
3803871Syz147064 break;
3813871Syz147064 }
3823871Syz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", s);
3833871Syz147064 return (buf);
3843871Syz147064 }
3853871Syz147064
3863871Syz147064 /*
3875895Syz147064 * Case 1: rename an existing link1 to a link2 that does not exist.
3885895Syz147064 * Result: <linkid1, link2>
3893871Syz147064 */
3905895Syz147064 static dladm_status_t
i_dladm_rename_link_c1(dladm_handle_t handle,datalink_id_t linkid1,const char * link1,const char * link2,uint32_t flags)3918453SAnurag.Maskey@Sun.COM i_dladm_rename_link_c1(dladm_handle_t handle, datalink_id_t linkid1,
3928453SAnurag.Maskey@Sun.COM const char *link1, const char *link2, uint32_t flags)
3935895Syz147064 {
3945895Syz147064 dld_ioc_rename_t dir;
3955895Syz147064 dladm_status_t status = DLADM_STATUS_OK;
3965895Syz147064
3975895Syz147064 /*
3985895Syz147064 * Link is currently available. Check to see whether anything is
3995895Syz147064 * holding this link to prevent a rename operation.
4005895Syz147064 */
4015895Syz147064 if (flags & DLADM_OPT_ACTIVE) {
4025895Syz147064 dir.dir_linkid1 = linkid1;
4035895Syz147064 dir.dir_linkid2 = DATALINK_INVALID_LINKID;
4045895Syz147064 (void) strlcpy(dir.dir_link, link2, MAXLINKNAMELEN);
4055895Syz147064
4068453SAnurag.Maskey@Sun.COM if (ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir) < 0) {
4075895Syz147064 status = dladm_errno2status(errno);
4085895Syz147064 return (status);
4095895Syz147064 }
4105895Syz147064 }
4115895Syz147064
4128453SAnurag.Maskey@Sun.COM status = dladm_remap_datalink_id(handle, linkid1, link2);
41310616SSebastien.Roy@Sun.COM if (status != DLADM_STATUS_OK && (flags & DLADM_OPT_ACTIVE)) {
41410616SSebastien.Roy@Sun.COM (void) strlcpy(dir.dir_link, link1, MAXLINKNAMELEN);
41510616SSebastien.Roy@Sun.COM (void) ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir);
4165895Syz147064 }
4175895Syz147064 return (status);
4185895Syz147064 }
4195895Syz147064
4205895Syz147064 typedef struct link_hold_arg_s {
4215895Syz147064 datalink_id_t linkid;
4225895Syz147064 datalink_id_t holder;
4235895Syz147064 uint32_t flags;
4245895Syz147064 } link_hold_arg_t;
4255895Syz147064
4265895Syz147064 static int
i_dladm_aggr_link_hold(dladm_handle_t handle,datalink_id_t aggrid,void * arg)4278453SAnurag.Maskey@Sun.COM i_dladm_aggr_link_hold(dladm_handle_t handle, datalink_id_t aggrid, void *arg)
4285895Syz147064 {
4295895Syz147064 link_hold_arg_t *hold_arg = arg;
4305895Syz147064 dladm_aggr_grp_attr_t ginfo;
4315895Syz147064 dladm_status_t status;
4325895Syz147064 int i;
4335895Syz147064
4348453SAnurag.Maskey@Sun.COM status = dladm_aggr_info(handle, aggrid, &ginfo, hold_arg->flags);
4355895Syz147064 if (status != DLADM_STATUS_OK)
4365895Syz147064 return (DLADM_WALK_CONTINUE);
4375895Syz147064
4385895Syz147064 for (i = 0; i < ginfo.lg_nports; i++) {
4395895Syz147064 if (ginfo.lg_ports[i].lp_linkid == hold_arg->linkid) {
4405895Syz147064 hold_arg->holder = aggrid;
4415895Syz147064 return (DLADM_WALK_TERMINATE);
4425895Syz147064 }
4435895Syz147064 }
4445895Syz147064 return (DLADM_WALK_CONTINUE);
4455895Syz147064 }
4465895Syz147064
4475895Syz147064 static int
i_dladm_vlan_link_hold(dladm_handle_t handle,datalink_id_t vlanid,void * arg)4488453SAnurag.Maskey@Sun.COM i_dladm_vlan_link_hold(dladm_handle_t handle, datalink_id_t vlanid, void *arg)
4495895Syz147064 {
4505895Syz147064 link_hold_arg_t *hold_arg = arg;
4515895Syz147064 dladm_vlan_attr_t vinfo;
4525895Syz147064 dladm_status_t status;
4535895Syz147064
4548453SAnurag.Maskey@Sun.COM status = dladm_vlan_info(handle, vlanid, &vinfo, hold_arg->flags);
4555895Syz147064 if (status != DLADM_STATUS_OK)
4565895Syz147064 return (DLADM_WALK_CONTINUE);
4575895Syz147064
4585895Syz147064 if (vinfo.dv_linkid == hold_arg->linkid) {
4595895Syz147064 hold_arg->holder = vlanid;
4605895Syz147064 return (DLADM_WALK_TERMINATE);
4615895Syz147064 }
4625895Syz147064 return (DLADM_WALK_CONTINUE);
4635895Syz147064 }
4645895Syz147064
4655895Syz147064 /*
4665895Syz147064 * Case 2: rename an available physical link link1 to a REMOVED physical link
4675895Syz147064 * link2. As a result, link1 directly inherits all datalinks configured
4685895Syz147064 * over link2 (linkid2).
4695895Syz147064 * Result: <linkid2, link2, link1_phymaj, link1_phyinst, link1_devname,
4705895Syz147064 * link2_other_attr>
4715895Syz147064 */
4725895Syz147064 static dladm_status_t
i_dladm_rename_link_c2(dladm_handle_t handle,datalink_id_t linkid1,datalink_id_t linkid2)4738453SAnurag.Maskey@Sun.COM i_dladm_rename_link_c2(dladm_handle_t handle, datalink_id_t linkid1,
4748453SAnurag.Maskey@Sun.COM datalink_id_t linkid2)
4753871Syz147064 {
4765895Syz147064 rcm_handle_t *rcm_hdl = NULL;
4775895Syz147064 nvlist_t *nvl = NULL;
4785895Syz147064 link_hold_arg_t arg;
4795895Syz147064 dld_ioc_rename_t dir;
4805895Syz147064 dladm_conf_t conf1, conf2;
4815895Syz147064 char devname[MAXLINKNAMELEN];
4825895Syz147064 uint64_t phymaj, phyinst;
4835895Syz147064 dladm_status_t status = DLADM_STATUS_OK;
4845895Syz147064
4855895Syz147064 /*
4865895Syz147064 * First check if linkid1 is associated with any persistent
4875895Syz147064 * aggregations or VLANs. If yes, return BUSY.
4885895Syz147064 */
4895895Syz147064 arg.linkid = linkid1;
4905895Syz147064 arg.holder = DATALINK_INVALID_LINKID;
4915895Syz147064 arg.flags = DLADM_OPT_PERSIST;
4928453SAnurag.Maskey@Sun.COM (void) dladm_walk_datalink_id(i_dladm_aggr_link_hold, handle, &arg,
4935895Syz147064 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
4945895Syz147064 if (arg.holder != DATALINK_INVALID_LINKID)
4955895Syz147064 return (DLADM_STATUS_LINKBUSY);
4965895Syz147064
4975895Syz147064 arg.flags = DLADM_OPT_PERSIST;
4988453SAnurag.Maskey@Sun.COM (void) dladm_walk_datalink_id(i_dladm_vlan_link_hold, handle, &arg,
4995895Syz147064 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
5005895Syz147064 if (arg.holder != DATALINK_INVALID_LINKID)
5015895Syz147064 return (DLADM_STATUS_LINKBUSY);
5025895Syz147064
5035895Syz147064 /*
5045895Syz147064 * Send DLDIOC_RENAME to request to rename link1's linkid to
5055895Syz147064 * be linkid2. This will check whether link1 is used by any
5065895Syz147064 * aggregations or VLANs, or is held by any application. If yes,
5075895Syz147064 * return failure.
5085895Syz147064 */
5095895Syz147064 dir.dir_linkid1 = linkid1;
5105895Syz147064 dir.dir_linkid2 = linkid2;
5118453SAnurag.Maskey@Sun.COM if (ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir) < 0)
5125895Syz147064 status = dladm_errno2status(errno);
5135895Syz147064
5145895Syz147064 if (status != DLADM_STATUS_OK) {
5155895Syz147064 return (status);
5165895Syz147064 }
5175895Syz147064
5185895Syz147064 /*
5195895Syz147064 * Now change the phymaj, phyinst and devname associated with linkid1
5205895Syz147064 * to be associated with linkid2. Before doing that, the old active
5215895Syz147064 * linkprop of linkid1 should be deleted.
5225895Syz147064 */
5238453SAnurag.Maskey@Sun.COM (void) dladm_set_linkprop(handle, linkid1, NULL, NULL, 0,
5248453SAnurag.Maskey@Sun.COM DLADM_OPT_ACTIVE);
5255895Syz147064
526*12824SCathy.Zhou@Sun.COM if (((status = dladm_getsnap_conf(handle, linkid1, &conf1)) !=
5278453SAnurag.Maskey@Sun.COM DLADM_STATUS_OK) ||
5288453SAnurag.Maskey@Sun.COM ((status = dladm_get_conf_field(handle, conf1, FDEVNAME, devname,
5295895Syz147064 MAXLINKNAMELEN)) != DLADM_STATUS_OK) ||
5308453SAnurag.Maskey@Sun.COM ((status = dladm_get_conf_field(handle, conf1, FPHYMAJ, &phymaj,
5315895Syz147064 sizeof (uint64_t))) != DLADM_STATUS_OK) ||
5328453SAnurag.Maskey@Sun.COM ((status = dladm_get_conf_field(handle, conf1, FPHYINST, &phyinst,
5335895Syz147064 sizeof (uint64_t))) != DLADM_STATUS_OK) ||
534*12824SCathy.Zhou@Sun.COM ((status = dladm_open_conf(handle, linkid2, &conf2)) !=
5358453SAnurag.Maskey@Sun.COM DLADM_STATUS_OK)) {
5365895Syz147064 dir.dir_linkid1 = linkid2;
5375895Syz147064 dir.dir_linkid2 = linkid1;
5388453SAnurag.Maskey@Sun.COM (void) dladm_init_linkprop(handle, linkid1, B_FALSE);
5398453SAnurag.Maskey@Sun.COM (void) ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir);
5405895Syz147064 return (status);
5415895Syz147064 }
5425895Syz147064
5438453SAnurag.Maskey@Sun.COM dladm_destroy_conf(handle, conf1);
5448453SAnurag.Maskey@Sun.COM (void) dladm_set_conf_field(handle, conf2, FDEVNAME, DLADM_TYPE_STR,
5458453SAnurag.Maskey@Sun.COM devname);
5468453SAnurag.Maskey@Sun.COM (void) dladm_set_conf_field(handle, conf2, FPHYMAJ, DLADM_TYPE_UINT64,
5478453SAnurag.Maskey@Sun.COM &phymaj);
5488453SAnurag.Maskey@Sun.COM (void) dladm_set_conf_field(handle, conf2, FPHYINST,
5495895Syz147064 DLADM_TYPE_UINT64, &phyinst);
5508453SAnurag.Maskey@Sun.COM (void) dladm_write_conf(handle, conf2);
5518453SAnurag.Maskey@Sun.COM dladm_destroy_conf(handle, conf2);
5525895Syz147064
5535895Syz147064 /*
5545895Syz147064 * Delete link1 and mark link2 up.
5555895Syz147064 */
55610616SSebastien.Roy@Sun.COM (void) dladm_remove_conf(handle, linkid1);
5578453SAnurag.Maskey@Sun.COM (void) dladm_destroy_datalink_id(handle, linkid1, DLADM_OPT_ACTIVE |
5585895Syz147064 DLADM_OPT_PERSIST);
5598453SAnurag.Maskey@Sun.COM (void) dladm_up_datalink_id(handle, linkid2);
5605895Syz147064
5615895Syz147064 /*
5625895Syz147064 * Now generate the RCM_RESOURCE_LINK_NEW sysevent which can be
5635895Syz147064 * consumed by the RCM framework to restore all the datalink and
5645895Syz147064 * IP configuration.
5655895Syz147064 */
5665895Syz147064 status = DLADM_STATUS_FAILED;
5675895Syz147064 if ((nvlist_alloc(&nvl, 0, 0) != 0) ||
5685895Syz147064 (nvlist_add_uint64(nvl, RCM_NV_LINKID, linkid2) != 0)) {
5695895Syz147064 goto done;
5705895Syz147064 }
5715895Syz147064
5725895Syz147064 if (rcm_alloc_handle(NULL, 0, NULL, &rcm_hdl) != RCM_SUCCESS)
5735895Syz147064 goto done;
5745895Syz147064
5755895Syz147064 if (rcm_notify_event(rcm_hdl, RCM_RESOURCE_LINK_NEW, 0, nvl, NULL) ==
5765895Syz147064 RCM_SUCCESS) {
5775895Syz147064 status = DLADM_STATUS_OK;
5785895Syz147064 }
5795895Syz147064
5805895Syz147064 done:
5815895Syz147064 if (rcm_hdl != NULL)
5825895Syz147064 (void) rcm_free_handle(rcm_hdl);
5835895Syz147064 if (nvl != NULL)
5845895Syz147064 nvlist_free(nvl);
5855895Syz147064 return (status);
5863871Syz147064 }
5873871Syz147064
5883871Syz147064 /*
5895895Syz147064 * case 3: rename a non-existent link to a REMOVED physical link.
5905895Syz147064 * Set the removed physical link's device name to link1, so that
5915895Syz147064 * when link1 attaches, it inherits all the link configuration of
5925895Syz147064 * the removed physical link.
5933871Syz147064 */
5945895Syz147064 static dladm_status_t
i_dladm_rename_link_c3(dladm_handle_t handle,const char * link1,datalink_id_t linkid2)5958453SAnurag.Maskey@Sun.COM i_dladm_rename_link_c3(dladm_handle_t handle, const char *link1,
5968453SAnurag.Maskey@Sun.COM datalink_id_t linkid2)
5975895Syz147064 {
5985895Syz147064 dladm_conf_t conf;
5995895Syz147064 dladm_status_t status;
6005895Syz147064
6015895Syz147064 if (!dladm_valid_linkname(link1))
6025895Syz147064 return (DLADM_STATUS_LINKINVAL);
6035895Syz147064
604*12824SCathy.Zhou@Sun.COM status = dladm_open_conf(handle, linkid2, &conf);
6055895Syz147064 if (status != DLADM_STATUS_OK)
6065895Syz147064 goto done;
6075895Syz147064
6088453SAnurag.Maskey@Sun.COM if ((status = dladm_set_conf_field(handle, conf, FDEVNAME,
6098453SAnurag.Maskey@Sun.COM DLADM_TYPE_STR, link1)) == DLADM_STATUS_OK) {
6108453SAnurag.Maskey@Sun.COM status = dladm_write_conf(handle, conf);
6115895Syz147064 }
6125895Syz147064
6138453SAnurag.Maskey@Sun.COM dladm_destroy_conf(handle, conf);
6145895Syz147064
6155895Syz147064 done:
6165895Syz147064 return (status);
6175895Syz147064 }
6185895Syz147064
6195895Syz147064 dladm_status_t
dladm_rename_link(dladm_handle_t handle,const char * link1,const char * link2)6208453SAnurag.Maskey@Sun.COM dladm_rename_link(dladm_handle_t handle, const char *link1, const char *link2)
6215895Syz147064 {
6225895Syz147064 datalink_id_t linkid1 = DATALINK_INVALID_LINKID;
6235895Syz147064 datalink_id_t linkid2 = DATALINK_INVALID_LINKID;
6245895Syz147064 uint32_t flags1, flags2;
6255895Syz147064 datalink_class_t class1, class2;
6265895Syz147064 uint32_t media1, media2;
6275895Syz147064 boolean_t remphy2 = B_FALSE;
6285895Syz147064 dladm_status_t status;
6295895Syz147064
6308453SAnurag.Maskey@Sun.COM (void) dladm_name2info(handle, link1, &linkid1, &flags1, &class1,
6318453SAnurag.Maskey@Sun.COM &media1);
6328453SAnurag.Maskey@Sun.COM if ((dladm_name2info(handle, link2, &linkid2, &flags2, &class2,
6338453SAnurag.Maskey@Sun.COM &media2) == DLADM_STATUS_OK) && (class2 == DATALINK_CLASS_PHYS) &&
6345895Syz147064 (flags2 == DLADM_OPT_PERSIST)) {
6355895Syz147064 /*
6365895Syz147064 * see whether link2 is a removed physical link.
6375895Syz147064 */
6385895Syz147064 remphy2 = B_TRUE;
6395895Syz147064 }
6405895Syz147064
6415895Syz147064 if (linkid1 != DATALINK_INVALID_LINKID) {
6425895Syz147064 if (linkid2 == DATALINK_INVALID_LINKID) {
6435895Syz147064 /*
6445895Syz147064 * case 1: rename an existing link to a link that
6455895Syz147064 * does not exist.
6465895Syz147064 */
6478453SAnurag.Maskey@Sun.COM status = i_dladm_rename_link_c1(handle, linkid1, link1,
6488453SAnurag.Maskey@Sun.COM link2, flags1);
6495895Syz147064 } else if (remphy2) {
6505895Syz147064 /*
6515895Syz147064 * case 2: rename an available link to a REMOVED
6525895Syz147064 * physical link. Return failure if link1 is not
6535895Syz147064 * an active physical link.
6545895Syz147064 */
6555895Syz147064 if ((class1 != class2) || (media1 != media2) ||
6565895Syz147064 !(flags1 & DLADM_OPT_ACTIVE)) {
6575895Syz147064 status = DLADM_STATUS_BADARG;
6585895Syz147064 } else {
6598453SAnurag.Maskey@Sun.COM status = i_dladm_rename_link_c2(handle, linkid1,
6605895Syz147064 linkid2);
6615895Syz147064 }
6625895Syz147064 } else {
6635895Syz147064 status = DLADM_STATUS_EXIST;
6645895Syz147064 }
6655895Syz147064 } else if (remphy2) {
6668453SAnurag.Maskey@Sun.COM status = i_dladm_rename_link_c3(handle, link1, linkid2);
6675895Syz147064 } else {
6685895Syz147064 status = DLADM_STATUS_NOTFOUND;
6695895Syz147064 }
6705895Syz147064 return (status);
6715895Syz147064 }
6725895Syz147064
6735895Syz147064 typedef struct consumer_del_phys_arg_s {
6745895Syz147064 datalink_id_t linkid;
6755895Syz147064 } consumer_del_phys_arg_t;
6765895Syz147064
6775895Syz147064 static int
i_dladm_vlan_link_del(dladm_handle_t handle,datalink_id_t vlanid,void * arg)6788453SAnurag.Maskey@Sun.COM i_dladm_vlan_link_del(dladm_handle_t handle, datalink_id_t vlanid, void *arg)
6795895Syz147064 {
6805895Syz147064 consumer_del_phys_arg_t *del_arg = arg;
6815895Syz147064 dladm_vlan_attr_t vinfo;
6825895Syz147064 dladm_status_t status;
6835895Syz147064
6848453SAnurag.Maskey@Sun.COM status = dladm_vlan_info(handle, vlanid, &vinfo, DLADM_OPT_PERSIST);
6855895Syz147064 if (status != DLADM_STATUS_OK)
6865895Syz147064 return (DLADM_WALK_CONTINUE);
6875895Syz147064
6885895Syz147064 if (vinfo.dv_linkid == del_arg->linkid)
6898453SAnurag.Maskey@Sun.COM (void) dladm_vlan_delete(handle, vlanid, DLADM_OPT_PERSIST);
6905895Syz147064 return (DLADM_WALK_CONTINUE);
6915895Syz147064 }
6925895Syz147064
6935895Syz147064 static int
i_dladm_part_link_del(dladm_handle_t handle,datalink_id_t partid,void * arg)69412163SRamaswamy.Tummala@Sun.COM i_dladm_part_link_del(dladm_handle_t handle, datalink_id_t partid, void *arg)
69512163SRamaswamy.Tummala@Sun.COM {
69612163SRamaswamy.Tummala@Sun.COM consumer_del_phys_arg_t *del_arg = arg;
69712163SRamaswamy.Tummala@Sun.COM dladm_part_attr_t pinfo;
69812163SRamaswamy.Tummala@Sun.COM dladm_status_t status;
69912163SRamaswamy.Tummala@Sun.COM
70012163SRamaswamy.Tummala@Sun.COM status = dladm_part_info(handle, partid, &pinfo, DLADM_OPT_PERSIST);
70112163SRamaswamy.Tummala@Sun.COM if (status != DLADM_STATUS_OK)
70212163SRamaswamy.Tummala@Sun.COM return (DLADM_WALK_CONTINUE);
70312163SRamaswamy.Tummala@Sun.COM
70412163SRamaswamy.Tummala@Sun.COM if (pinfo.dia_physlinkid == del_arg->linkid)
70512163SRamaswamy.Tummala@Sun.COM (void) dladm_part_delete(handle, partid, DLADM_OPT_PERSIST);
70612163SRamaswamy.Tummala@Sun.COM return (DLADM_WALK_CONTINUE);
70712163SRamaswamy.Tummala@Sun.COM }
70812163SRamaswamy.Tummala@Sun.COM
70912163SRamaswamy.Tummala@Sun.COM static int
i_dladm_aggr_link_del(dladm_handle_t handle,datalink_id_t aggrid,void * arg)7108453SAnurag.Maskey@Sun.COM i_dladm_aggr_link_del(dladm_handle_t handle, datalink_id_t aggrid, void *arg)
7115895Syz147064 {
7125895Syz147064 consumer_del_phys_arg_t *del_arg = arg;
7135895Syz147064 dladm_aggr_grp_attr_t ginfo;
7145895Syz147064 dladm_status_t status;
7155895Syz147064 dladm_aggr_port_attr_db_t port[1];
7165895Syz147064 int i;
7175895Syz147064
7188453SAnurag.Maskey@Sun.COM status = dladm_aggr_info(handle, aggrid, &ginfo, DLADM_OPT_PERSIST);
7195895Syz147064 if (status != DLADM_STATUS_OK)
7205895Syz147064 return (DLADM_WALK_CONTINUE);
7215895Syz147064
7225895Syz147064 for (i = 0; i < ginfo.lg_nports; i++)
7235895Syz147064 if (ginfo.lg_ports[i].lp_linkid == del_arg->linkid)
7245895Syz147064 break;
7255895Syz147064
7265895Syz147064 if (i != ginfo.lg_nports) {
7275895Syz147064 if (ginfo.lg_nports == 1 && i == 0) {
7285895Syz147064 consumer_del_phys_arg_t aggr_del_arg;
7295895Syz147064
7305895Syz147064 /*
7315895Syz147064 * First delete all the VLANs on this aggregation, then
7325895Syz147064 * delete the aggregation itself.
7335895Syz147064 */
7345895Syz147064 aggr_del_arg.linkid = aggrid;
7355895Syz147064 (void) dladm_walk_datalink_id(i_dladm_vlan_link_del,
7368453SAnurag.Maskey@Sun.COM handle, &aggr_del_arg, DATALINK_CLASS_VLAN,
7375895Syz147064 DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
7388453SAnurag.Maskey@Sun.COM (void) dladm_aggr_delete(handle, aggrid,
7398453SAnurag.Maskey@Sun.COM DLADM_OPT_PERSIST);
7405895Syz147064 } else {
7415895Syz147064 port[0].lp_linkid = del_arg->linkid;
7428453SAnurag.Maskey@Sun.COM (void) dladm_aggr_remove(handle, aggrid, 1, port,
7435895Syz147064 DLADM_OPT_PERSIST);
7445895Syz147064 }
7455895Syz147064 }
7465895Syz147064 return (DLADM_WALK_CONTINUE);
7475895Syz147064 }
7485895Syz147064
7495895Syz147064 typedef struct del_phys_arg_s {
7505895Syz147064 dladm_status_t rval;
7515895Syz147064 } del_phys_arg_t;
7525895Syz147064
7535895Syz147064 static int
i_dladm_phys_delete(dladm_handle_t handle,datalink_id_t linkid,void * arg)7548453SAnurag.Maskey@Sun.COM i_dladm_phys_delete(dladm_handle_t handle, datalink_id_t linkid, void *arg)
7555895Syz147064 {
7565895Syz147064 uint32_t flags;
7575895Syz147064 datalink_class_t class;
7585895Syz147064 uint32_t media;
7595895Syz147064 dladm_status_t status = DLADM_STATUS_OK;
7605895Syz147064 del_phys_arg_t *del_phys_arg = arg;
7615895Syz147064 consumer_del_phys_arg_t del_arg;
7625895Syz147064
7638453SAnurag.Maskey@Sun.COM if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class,
7645895Syz147064 &media, NULL, 0)) != DLADM_STATUS_OK) {
7655895Syz147064 goto done;
7665895Syz147064 }
7675895Syz147064
7685895Syz147064 /*
7695895Syz147064 * see whether this link is a removed physical link.
7705895Syz147064 */
7715895Syz147064 if ((class != DATALINK_CLASS_PHYS) || !(flags & DLADM_OPT_PERSIST) ||
7725895Syz147064 (flags & DLADM_OPT_ACTIVE)) {
7735895Syz147064 status = DLADM_STATUS_BADARG;
7745895Syz147064 goto done;
7755895Syz147064 }
7765895Syz147064
7775895Syz147064 if (media == DL_ETHER) {
7785895Syz147064 del_arg.linkid = linkid;
7798453SAnurag.Maskey@Sun.COM (void) dladm_walk_datalink_id(i_dladm_aggr_link_del, handle,
7808453SAnurag.Maskey@Sun.COM &del_arg, DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE,
7815895Syz147064 DLADM_OPT_PERSIST);
7828453SAnurag.Maskey@Sun.COM (void) dladm_walk_datalink_id(i_dladm_vlan_link_del, handle,
7838453SAnurag.Maskey@Sun.COM &del_arg, DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE,
7845895Syz147064 DLADM_OPT_PERSIST);
78512163SRamaswamy.Tummala@Sun.COM } else if (media == DL_IB) {
78612163SRamaswamy.Tummala@Sun.COM del_arg.linkid = linkid;
78712163SRamaswamy.Tummala@Sun.COM (void) dladm_walk_datalink_id(i_dladm_part_link_del, handle,
78812163SRamaswamy.Tummala@Sun.COM &del_arg, DATALINK_CLASS_PART, DL_IB, DLADM_OPT_PERSIST);
7895895Syz147064 }
7905895Syz147064
79110616SSebastien.Roy@Sun.COM (void) dladm_remove_conf(handle, linkid);
7928453SAnurag.Maskey@Sun.COM (void) dladm_destroy_datalink_id(handle, linkid, DLADM_OPT_PERSIST);
7935895Syz147064 done:
7945895Syz147064 del_phys_arg->rval = status;
7955895Syz147064 return (DLADM_WALK_CONTINUE);
7965895Syz147064 }
7975895Syz147064
7985895Syz147064 dladm_status_t
dladm_phys_delete(dladm_handle_t handle,datalink_id_t linkid)7998453SAnurag.Maskey@Sun.COM dladm_phys_delete(dladm_handle_t handle, datalink_id_t linkid)
8005895Syz147064 {
8015895Syz147064 del_phys_arg_t arg = {DLADM_STATUS_OK};
8025895Syz147064
8035895Syz147064 if (linkid == DATALINK_ALL_LINKID) {
8048453SAnurag.Maskey@Sun.COM (void) dladm_walk_datalink_id(i_dladm_phys_delete, handle, &arg,
8055895Syz147064 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE,
8065895Syz147064 DLADM_OPT_PERSIST);
8075895Syz147064 return (DLADM_STATUS_OK);
8085895Syz147064 } else {
8098453SAnurag.Maskey@Sun.COM (void) i_dladm_phys_delete(handle, linkid, &arg);
8105895Syz147064 return (arg.rval);
8115895Syz147064 }
8125895Syz147064 }
8135895Syz147064
8145895Syz147064 dladm_status_t
dladm_phys_info(dladm_handle_t handle,datalink_id_t linkid,dladm_phys_attr_t * dpap,uint32_t flags)8158453SAnurag.Maskey@Sun.COM dladm_phys_info(dladm_handle_t handle, datalink_id_t linkid,
8168453SAnurag.Maskey@Sun.COM dladm_phys_attr_t *dpap, uint32_t flags)
8175895Syz147064 {
8185895Syz147064 dladm_status_t status;
8195895Syz147064
8205895Syz147064 assert(flags == DLADM_OPT_ACTIVE || flags == DLADM_OPT_PERSIST);
8215895Syz147064
8225895Syz147064 switch (flags) {
8235895Syz147064 case DLADM_OPT_PERSIST: {
8245895Syz147064 dladm_conf_t conf;
8255895Syz147064
826*12824SCathy.Zhou@Sun.COM status = dladm_getsnap_conf(handle, linkid, &conf);
8275895Syz147064 if (status != DLADM_STATUS_OK)
8285895Syz147064 return (status);
8295895Syz147064
8308453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FDEVNAME,
8318453SAnurag.Maskey@Sun.COM dpap->dp_dev, MAXLINKNAMELEN);
8328453SAnurag.Maskey@Sun.COM dladm_destroy_conf(handle, conf);
8335895Syz147064 return (status);
8345895Syz147064 }
8355895Syz147064 case DLADM_OPT_ACTIVE: {
8365895Syz147064 dld_ioc_phys_attr_t dip;
8375895Syz147064
8385895Syz147064 dip.dip_linkid = linkid;
8398453SAnurag.Maskey@Sun.COM if (ioctl(dladm_dld_fd(handle), DLDIOC_PHYS_ATTR, &dip) < 0) {
8405895Syz147064 status = dladm_errno2status(errno);
8415895Syz147064 return (status);
8425895Syz147064 }
8435895Syz147064 dpap->dp_novanity = dip.dip_novanity;
8445895Syz147064 (void) strlcpy(dpap->dp_dev, dip.dip_dev, MAXLINKNAMELEN);
8455895Syz147064 return (DLADM_STATUS_OK);
8465895Syz147064 }
8475895Syz147064 default:
8485895Syz147064 return (DLADM_STATUS_BADARG);
8495895Syz147064 }
8505895Syz147064 }
8515895Syz147064
8525895Syz147064 typedef struct i_walk_dev_state_s {
8535895Syz147064 const char *devname;
8545895Syz147064 datalink_id_t linkid;
8555895Syz147064 boolean_t found;
8565895Syz147064 } i_walk_dev_state_t;
8575895Syz147064
8583871Syz147064 int
i_dladm_walk_dev2linkid(dladm_handle_t handle,datalink_id_t linkid,void * arg)8598453SAnurag.Maskey@Sun.COM i_dladm_walk_dev2linkid(dladm_handle_t handle, datalink_id_t linkid, void *arg)
8605895Syz147064 {
8615895Syz147064 dladm_phys_attr_t dpa;
8625895Syz147064 dladm_status_t status;
8635895Syz147064 i_walk_dev_state_t *statep = arg;
8645895Syz147064
8658453SAnurag.Maskey@Sun.COM status = dladm_phys_info(handle, linkid, &dpa, DLADM_OPT_PERSIST);
8665895Syz147064 if ((status == DLADM_STATUS_OK) &&
8675895Syz147064 (strcmp(statep->devname, dpa.dp_dev) == 0)) {
8685895Syz147064 statep->found = B_TRUE;
8695895Syz147064 statep->linkid = linkid;
8705895Syz147064 return (DLADM_WALK_TERMINATE);
8715895Syz147064 }
8725895Syz147064 return (DLADM_WALK_CONTINUE);
8735895Syz147064 }
8745895Syz147064
8755895Syz147064 /*
8765895Syz147064 * Get the linkid from the physical device name.
8775895Syz147064 */
8785895Syz147064 dladm_status_t
dladm_dev2linkid(dladm_handle_t handle,const char * devname,datalink_id_t * linkidp)8798453SAnurag.Maskey@Sun.COM dladm_dev2linkid(dladm_handle_t handle, const char *devname,
8808453SAnurag.Maskey@Sun.COM datalink_id_t *linkidp)
8815895Syz147064 {
8825895Syz147064 i_walk_dev_state_t state;
8835895Syz147064
8845895Syz147064 state.found = B_FALSE;
8855895Syz147064 state.devname = devname;
8865895Syz147064
8878453SAnurag.Maskey@Sun.COM (void) dladm_walk_datalink_id(i_dladm_walk_dev2linkid, handle, &state,
8885895Syz147064 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
8895895Syz147064 if (state.found == B_TRUE) {
8905895Syz147064 *linkidp = state.linkid;
8915895Syz147064 return (DLADM_STATUS_OK);
8925895Syz147064 } else {
8935895Syz147064 return (dladm_errno2status(ENOENT));
8945895Syz147064 }
8955895Syz147064 }
8965895Syz147064
8975895Syz147064 static int
parse_devname(const char * devname,char * driver,uint_t * ppa,size_t maxlen)8985895Syz147064 parse_devname(const char *devname, char *driver, uint_t *ppa, size_t maxlen)
8995895Syz147064 {
9005895Syz147064 char *cp, *tp;
9015895Syz147064 int len;
9025895Syz147064
9035895Syz147064 /*
9045895Syz147064 * device name length must not be 0, and it must end with digit.
9055895Syz147064 */
9065895Syz147064 if (((len = strlen(devname)) == 0) || !isdigit(devname[len - 1]))
9075895Syz147064 return (EINVAL);
9085895Syz147064
9095895Syz147064 (void) strlcpy(driver, devname, maxlen);
9105895Syz147064 cp = (char *)&driver[len - 1];
9115895Syz147064
9125895Syz147064 for (tp = cp; isdigit(*tp); tp--) {
9135895Syz147064 if (tp <= driver)
9145895Syz147064 return (EINVAL);
9155895Syz147064 }
9165895Syz147064
9175895Syz147064 *ppa = atoi(tp + 1);
9185895Syz147064 *(tp + 1) = '\0';
9195895Syz147064 return (0);
9205895Syz147064 }
9215895Syz147064
9225895Syz147064 dladm_status_t
dladm_linkid2legacyname(dladm_handle_t handle,datalink_id_t linkid,char * dev,size_t len)9238453SAnurag.Maskey@Sun.COM dladm_linkid2legacyname(dladm_handle_t handle, datalink_id_t linkid, char *dev,
9248453SAnurag.Maskey@Sun.COM size_t len)
9253871Syz147064 {
9265895Syz147064 char devname[MAXLINKNAMELEN];
9275895Syz147064 uint16_t vid = VLAN_ID_NONE;
9285895Syz147064 datalink_class_t class;
9295895Syz147064 dladm_status_t status;
9305895Syz147064
9318453SAnurag.Maskey@Sun.COM status = dladm_datalink_id2info(handle, linkid, NULL, &class, NULL,
9328453SAnurag.Maskey@Sun.COM NULL, 0);
9335895Syz147064 if (status != DLADM_STATUS_OK)
9345895Syz147064 goto done;
9355895Syz147064
9365895Syz147064 /*
9375895Syz147064 * If this is a VLAN, we must first determine the class and linkid of
9385895Syz147064 * the link the VLAN has been created over.
9395895Syz147064 */
9405895Syz147064 if (class == DATALINK_CLASS_VLAN) {
9415895Syz147064 dladm_vlan_attr_t dva;
9425895Syz147064
9438453SAnurag.Maskey@Sun.COM status = dladm_vlan_info(handle, linkid, &dva,
9448453SAnurag.Maskey@Sun.COM DLADM_OPT_ACTIVE);
9455895Syz147064 if (status != DLADM_STATUS_OK)
9465895Syz147064 goto done;
9475895Syz147064 linkid = dva.dv_linkid;
9485895Syz147064 vid = dva.dv_vid;
9495895Syz147064
9508453SAnurag.Maskey@Sun.COM if ((status = dladm_datalink_id2info(handle, linkid, NULL,
9518453SAnurag.Maskey@Sun.COM &class, NULL, NULL, 0)) != DLADM_STATUS_OK) {
9525895Syz147064 goto done;
9535895Syz147064 }
9545895Syz147064 }
9555895Syz147064
9565895Syz147064 switch (class) {
9575895Syz147064 case DATALINK_CLASS_AGGR: {
9585895Syz147064 dladm_aggr_grp_attr_t dga;
9595895Syz147064
9608453SAnurag.Maskey@Sun.COM status = dladm_aggr_info(handle, linkid, &dga,
9618453SAnurag.Maskey@Sun.COM DLADM_OPT_ACTIVE);
9625895Syz147064 if (status != DLADM_STATUS_OK)
9635895Syz147064 goto done;
9645895Syz147064
9655895Syz147064 if (dga.lg_key == 0) {
9665895Syz147064 /*
9675895Syz147064 * If the key was not specified when the aggregation
9685895Syz147064 * is created, we cannot guess its /dev node name.
9695895Syz147064 */
9705895Syz147064 status = DLADM_STATUS_BADARG;
9715895Syz147064 goto done;
9725895Syz147064 }
9735895Syz147064 (void) snprintf(devname, MAXLINKNAMELEN, "aggr%d", dga.lg_key);
9745895Syz147064 break;
9755895Syz147064 }
9765895Syz147064 case DATALINK_CLASS_PHYS: {
9775895Syz147064 dladm_phys_attr_t dpa;
9785895Syz147064
9798453SAnurag.Maskey@Sun.COM status = dladm_phys_info(handle, linkid, &dpa,
9808453SAnurag.Maskey@Sun.COM DLADM_OPT_PERSIST);
9815895Syz147064 if (status != DLADM_STATUS_OK)
9825895Syz147064 goto done;
9835895Syz147064
9845895Syz147064 (void) strlcpy(devname, dpa.dp_dev, MAXLINKNAMELEN);
9855895Syz147064 break;
9865895Syz147064 }
9875895Syz147064 default:
9885895Syz147064 status = DLADM_STATUS_BADARG;
9895895Syz147064 goto done;
9905895Syz147064 }
9915895Syz147064
9925895Syz147064 if (vid != VLAN_ID_NONE) {
9935895Syz147064 char drv[MAXNAMELEN];
9945895Syz147064 uint_t ppa;
9955895Syz147064
9965895Syz147064 if (parse_devname(devname, drv, &ppa, MAXNAMELEN) != 0) {
9975895Syz147064 status = DLADM_STATUS_BADARG;
9985895Syz147064 goto done;
9995895Syz147064 }
10005895Syz147064 if (snprintf(dev, len, "%s%d", drv, vid * 1000 + ppa) >= len)
10015895Syz147064 status = DLADM_STATUS_TOOSMALL;
10025895Syz147064 } else {
10035895Syz147064 if (strlcpy(dev, devname, len) >= len)
10045895Syz147064 status = DLADM_STATUS_TOOSMALL;
10055895Syz147064 }
10065895Syz147064
10075895Syz147064 done:
10085895Syz147064 return (status);
10093871Syz147064 }
10105903Ssowmini
10115903Ssowmini dladm_status_t
dladm_parselink(const char * dev,char * provider,uint_t * ppa)10125903Ssowmini dladm_parselink(const char *dev, char *provider, uint_t *ppa)
10135903Ssowmini {
10145903Ssowmini ifspec_t ifsp;
10155903Ssowmini
10165903Ssowmini if (dev == NULL || !ifparse_ifspec(dev, &ifsp))
10175903Ssowmini return (DLADM_STATUS_LINKINVAL);
10185903Ssowmini
10195903Ssowmini if (provider != NULL)
10205903Ssowmini (void) strlcpy(provider, ifsp.ifsp_devnm, DLPI_LINKNAME_MAX);
10215903Ssowmini
10225903Ssowmini if (ppa != NULL)
10235903Ssowmini *ppa = ifsp.ifsp_ppa;
10245903Ssowmini
10255903Ssowmini return (DLADM_STATUS_OK);
10265903Ssowmini }
1027