15084Sjohnlev /*
25084Sjohnlev  * CDDL HEADER START
35084Sjohnlev  *
45084Sjohnlev  * The contents of this file are subject to the terms of the
55084Sjohnlev  * Common Development and Distribution License (the "License").
65084Sjohnlev  * You may not use this file except in compliance with the License.
75084Sjohnlev  *
85084Sjohnlev  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95084Sjohnlev  * or http://www.opensolaris.org/os/licensing.
105084Sjohnlev  * See the License for the specific language governing permissions
115084Sjohnlev  * and limitations under the License.
125084Sjohnlev  *
135084Sjohnlev  * When distributing Covered Code, include this CDDL HEADER in each
145084Sjohnlev  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155084Sjohnlev  * If applicable, add the following below this CDDL HEADER, with the
165084Sjohnlev  * fields enclosed by brackets "[]" replaced with your own identifying
175084Sjohnlev  * information: Portions Copyright [yyyy] [name of copyright owner]
185084Sjohnlev  *
195084Sjohnlev  * CDDL HEADER END
205084Sjohnlev  */
215084Sjohnlev /*
22*12824SCathy.Zhou@Sun.COM  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
235084Sjohnlev  */
245084Sjohnlev 
255084Sjohnlev #include <stdio.h>
265084Sjohnlev #include <sys/types.h>
275084Sjohnlev #include <sys/stat.h>
285084Sjohnlev #include <string.h>
295084Sjohnlev #include <fcntl.h>
305084Sjohnlev #include <unistd.h>
315084Sjohnlev #include <stropts.h>
325084Sjohnlev #include <stdlib.h>
335084Sjohnlev #include <errno.h>
345084Sjohnlev #include <strings.h>
355084Sjohnlev #include <libintl.h>
365084Sjohnlev #include <net/if_types.h>
375084Sjohnlev #include <net/if_dl.h>
388275SEric Cheng #include <sys/dld.h>
395084Sjohnlev #include <libdladm_impl.h>
4011076SCathy.Zhou@Sun.COM #include <libvrrpadm.h>
415895Syz147064 #include <libdllink.h>
4210491SRishi.Srivatsavai@Sun.COM #include <libdlbridge.h>
435084Sjohnlev #include <libdlvnic.h>
445084Sjohnlev 
455084Sjohnlev /*
465084Sjohnlev  * VNIC administration library.
475084Sjohnlev  */
485084Sjohnlev 
498275SEric Cheng /*
508275SEric Cheng  * Default random MAC address prefix (locally administered).
518275SEric Cheng  */
528275SEric Cheng static char dladm_vnic_def_prefix[] = {0x02, 0x08, 0x20};
538275SEric Cheng 
548453SAnurag.Maskey@Sun.COM static dladm_status_t	dladm_vnic_persist_conf(dladm_handle_t,
558453SAnurag.Maskey@Sun.COM 			    const char *name, dladm_vnic_attr_t *,
568453SAnurag.Maskey@Sun.COM 			    datalink_class_t);
578275SEric Cheng static const char	*dladm_vnic_macaddr2str(const uchar_t *, char *);
588275SEric Cheng static dladm_status_t	dladm_vnic_str2macaddr(const char *, uchar_t *);
595084Sjohnlev 
608275SEric Cheng /*
618275SEric Cheng  * Convert a diagnostic returned by the kernel into a dladm_status_t.
628275SEric Cheng  */
638275SEric Cheng static dladm_status_t
648275SEric Cheng dladm_vnic_diag2status(vnic_ioc_diag_t ioc_diag)
658275SEric Cheng {
668275SEric Cheng 	switch (ioc_diag) {
6711076SCathy.Zhou@Sun.COM 	case VNIC_IOC_DIAG_NONE:
6811076SCathy.Zhou@Sun.COM 		return (DLADM_STATUS_OK);
698275SEric Cheng 	case VNIC_IOC_DIAG_MACADDRLEN_INVALID:
708275SEric Cheng 		return (DLADM_STATUS_INVALIDMACADDRLEN);
718275SEric Cheng 	case VNIC_IOC_DIAG_MACADDR_NIC:
728275SEric Cheng 		return (DLADM_STATUS_INVALIDMACADDRNIC);
738275SEric Cheng 	case VNIC_IOC_DIAG_MACADDR_INUSE:
748275SEric Cheng 		return (DLADM_STATUS_INVALIDMACADDRINUSE);
758275SEric Cheng 	case VNIC_IOC_DIAG_MACFACTORYSLOTINVALID:
768275SEric Cheng 		return (DLADM_STATUS_MACFACTORYSLOTINVALID);
778275SEric Cheng 	case VNIC_IOC_DIAG_MACFACTORYSLOTUSED:
788275SEric Cheng 		return (DLADM_STATUS_MACFACTORYSLOTUSED);
798275SEric Cheng 	case VNIC_IOC_DIAG_MACFACTORYSLOTALLUSED:
808275SEric Cheng 		return (DLADM_STATUS_MACFACTORYSLOTALLUSED);
818275SEric Cheng 	case VNIC_IOC_DIAG_MACFACTORYNOTSUP:
828275SEric Cheng 		return (DLADM_STATUS_MACFACTORYNOTSUP);
838275SEric Cheng 	case VNIC_IOC_DIAG_MACPREFIX_INVALID:
848275SEric Cheng 		return (DLADM_STATUS_INVALIDMACPREFIX);
858275SEric Cheng 	case VNIC_IOC_DIAG_MACPREFIXLEN_INVALID:
868275SEric Cheng 		return (DLADM_STATUS_INVALIDMACPREFIXLEN);
878275SEric Cheng 	case VNIC_IOC_DIAG_MACMARGIN_INVALID:
888275SEric Cheng 		return (DLADM_STATUS_INVALID_MACMARGIN);
898275SEric Cheng 	case VNIC_IOC_DIAG_NO_HWRINGS:
908275SEric Cheng 		return (DLADM_STATUS_NO_HWRINGS);
9111076SCathy.Zhou@Sun.COM 	case VNIC_IOC_DIAG_MACADDR_INVALID:
9211076SCathy.Zhou@Sun.COM 		return (DLADM_STATUS_INVALIDMACADDR);
9311076SCathy.Zhou@Sun.COM 	default:
9411076SCathy.Zhou@Sun.COM 		return (DLADM_STATUS_FAILED);
958275SEric Cheng 	}
968275SEric Cheng }
975084Sjohnlev 
985084Sjohnlev /*
995084Sjohnlev  * Send a create command to the VNIC driver.
1005084Sjohnlev  */
1018275SEric Cheng dladm_status_t
1028453SAnurag.Maskey@Sun.COM i_dladm_vnic_create_sys(dladm_handle_t handle, dladm_vnic_attr_t *attr)
1035084Sjohnlev {
1048453SAnurag.Maskey@Sun.COM 	int rc;
1055084Sjohnlev 	vnic_ioc_create_t ioc;
1068275SEric Cheng 	dladm_status_t status = DLADM_STATUS_OK;
1075084Sjohnlev 
1088275SEric Cheng 	bzero(&ioc, sizeof (ioc));
1098275SEric Cheng 	ioc.vc_vnic_id = attr->va_vnic_id;
1108275SEric Cheng 	ioc.vc_link_id = attr->va_link_id;
1118275SEric Cheng 	ioc.vc_mac_addr_type = attr->va_mac_addr_type;
1128275SEric Cheng 	ioc.vc_mac_len = attr->va_mac_len;
1138275SEric Cheng 	ioc.vc_mac_slot = attr->va_mac_slot;
1148275SEric Cheng 	ioc.vc_mac_prefix_len = attr->va_mac_prefix_len;
1158275SEric Cheng 	ioc.vc_vid = attr->va_vid;
11611076SCathy.Zhou@Sun.COM 	ioc.vc_vrid = attr->va_vrid;
11711076SCathy.Zhou@Sun.COM 	ioc.vc_af = attr->va_af;
1188275SEric Cheng 	ioc.vc_flags = attr->va_force ? VNIC_IOC_CREATE_FORCE : 0;
1195084Sjohnlev 
1208275SEric Cheng 	if (attr->va_mac_len > 0 || ioc.vc_mac_prefix_len > 0)
1218275SEric Cheng 		bcopy(attr->va_mac_addr, ioc.vc_mac_addr, MAXMACADDRLEN);
1228275SEric Cheng 	bcopy(&attr->va_resource_props, &ioc.vc_resource_props,
1238275SEric Cheng 	    sizeof (mac_resource_props_t));
1248275SEric Cheng 	if (attr->va_link_id == DATALINK_INVALID_LINKID)
1258275SEric Cheng 		ioc.vc_flags |= VNIC_IOC_CREATE_ANCHOR;
1265084Sjohnlev 
1278453SAnurag.Maskey@Sun.COM 	rc = ioctl(dladm_dld_fd(handle), VNIC_IOC_CREATE, &ioc);
1288275SEric Cheng 	if (rc < 0)
1298275SEric Cheng 		status = dladm_errno2status(errno);
1308275SEric Cheng 
1318275SEric Cheng 	if (status != DLADM_STATUS_OK) {
1328275SEric Cheng 		if (ioc.vc_diag != VNIC_IOC_DIAG_NONE)
1338275SEric Cheng 			status = dladm_vnic_diag2status(ioc.vc_diag);
1348275SEric Cheng 	}
1358275SEric Cheng 	if (status != DLADM_STATUS_OK)
1368275SEric Cheng 		return (status);
1378275SEric Cheng 
1388275SEric Cheng 	attr->va_mac_addr_type = ioc.vc_mac_addr_type;
1398275SEric Cheng 	switch (ioc.vc_mac_addr_type) {
1408275SEric Cheng 	case VNIC_MAC_ADDR_TYPE_FACTORY:
1418275SEric Cheng 		attr->va_mac_slot = ioc.vc_mac_slot;
1428275SEric Cheng 		break;
1438275SEric Cheng 	case VNIC_MAC_ADDR_TYPE_RANDOM:
1448275SEric Cheng 		bcopy(ioc.vc_mac_addr, attr->va_mac_addr, MAXMACADDRLEN);
1458275SEric Cheng 		attr->va_mac_len = ioc.vc_mac_len;
1468275SEric Cheng 		break;
1478275SEric Cheng 	}
1488275SEric Cheng 	return (status);
1498275SEric Cheng }
1508275SEric Cheng 
1518275SEric Cheng /*
1528275SEric Cheng  * Get the configuration information of the given VNIC.
1538275SEric Cheng  */
1548275SEric Cheng static dladm_status_t
1558453SAnurag.Maskey@Sun.COM i_dladm_vnic_info_active(dladm_handle_t handle, datalink_id_t linkid,
1568453SAnurag.Maskey@Sun.COM     dladm_vnic_attr_t *attrp)
1578275SEric Cheng {
1588275SEric Cheng 	vnic_ioc_info_t ioc;
1598275SEric Cheng 	vnic_info_t *vnic;
1608453SAnurag.Maskey@Sun.COM 	int rc;
1618275SEric Cheng 	dladm_status_t status = DLADM_STATUS_OK;
1628275SEric Cheng 
1638275SEric Cheng 	bzero(&ioc, sizeof (ioc));
1648275SEric Cheng 	vnic = &ioc.vi_info;
1658275SEric Cheng 	vnic->vn_vnic_id = linkid;
1668275SEric Cheng 
1678453SAnurag.Maskey@Sun.COM 	rc = ioctl(dladm_dld_fd(handle), VNIC_IOC_INFO, &ioc);
1688275SEric Cheng 	if (rc != 0) {
1698275SEric Cheng 		status = dladm_errno2status(errno);
1708275SEric Cheng 		goto bail;
1718275SEric Cheng 	}
1728275SEric Cheng 
1738275SEric Cheng 	attrp->va_vnic_id = vnic->vn_vnic_id;
1748275SEric Cheng 	attrp->va_link_id = vnic->vn_link_id;
1758275SEric Cheng 	attrp->va_mac_addr_type = vnic->vn_mac_addr_type;
1768275SEric Cheng 	bcopy(vnic->vn_mac_addr, attrp->va_mac_addr, MAXMACADDRLEN);
1778275SEric Cheng 	attrp->va_mac_len = vnic->vn_mac_len;
1788275SEric Cheng 	attrp->va_mac_slot = vnic->vn_mac_slot;
1798275SEric Cheng 	attrp->va_mac_prefix_len = vnic->vn_mac_prefix_len;
1808275SEric Cheng 	attrp->va_vid = vnic->vn_vid;
18111076SCathy.Zhou@Sun.COM 	attrp->va_vrid = vnic->vn_vrid;
18211076SCathy.Zhou@Sun.COM 	attrp->va_af = vnic->vn_af;
1838275SEric Cheng 	attrp->va_force = vnic->vn_force;
1848275SEric Cheng 
1858275SEric Cheng bail:
1868275SEric Cheng 	return (status);
1878275SEric Cheng }
1888275SEric Cheng 
1898275SEric Cheng static dladm_status_t
1908453SAnurag.Maskey@Sun.COM i_dladm_vnic_info_persist(dladm_handle_t handle, datalink_id_t linkid,
1918453SAnurag.Maskey@Sun.COM     dladm_vnic_attr_t *attrp)
1928275SEric Cheng {
1938275SEric Cheng 	dladm_conf_t conf;
1948275SEric Cheng 	dladm_status_t status;
1958275SEric Cheng 	char macstr[ETHERADDRL * 3];
19610616SSebastien.Roy@Sun.COM 	char linkover[MAXLINKNAMELEN];
1978275SEric Cheng 	uint64_t u64;
1988275SEric Cheng 	datalink_class_t class;
1998275SEric Cheng 
2008275SEric Cheng 	attrp->va_vnic_id = linkid;
201*12824SCathy.Zhou@Sun.COM 	if ((status = dladm_getsnap_conf(handle, linkid, &conf)) !=
2028453SAnurag.Maskey@Sun.COM 	    DLADM_STATUS_OK)
2038275SEric Cheng 		return (status);
2048275SEric Cheng 
20510616SSebastien.Roy@Sun.COM 	status = dladm_get_conf_field(handle, conf, FLINKOVER, linkover,
20610616SSebastien.Roy@Sun.COM 	    sizeof (linkover));
20710616SSebastien.Roy@Sun.COM 	if (status != DLADM_STATUS_OK) {
20810616SSebastien.Roy@Sun.COM 		/*
20910616SSebastien.Roy@Sun.COM 		 * This isn't an error, etherstubs don't have a FLINKOVER
21010616SSebastien.Roy@Sun.COM 		 * property.
21110616SSebastien.Roy@Sun.COM 		 */
21210616SSebastien.Roy@Sun.COM 		attrp->va_link_id = DATALINK_INVALID_LINKID;
21310616SSebastien.Roy@Sun.COM 	} else {
21410616SSebastien.Roy@Sun.COM 		if ((status = dladm_name2info(handle, linkover,
21510616SSebastien.Roy@Sun.COM 		    &attrp->va_link_id, NULL, NULL, NULL)) != DLADM_STATUS_OK)
21610616SSebastien.Roy@Sun.COM 			goto done;
21710616SSebastien.Roy@Sun.COM 	}
2188275SEric Cheng 
2198453SAnurag.Maskey@Sun.COM 	if ((status = dladm_datalink_id2info(handle, linkid, NULL, &class,
2208275SEric Cheng 	    NULL, NULL, 0)) != DLADM_STATUS_OK)
2218275SEric Cheng 		goto done;
2228275SEric Cheng 
2238275SEric Cheng 	if (class == DATALINK_CLASS_VLAN) {
2248275SEric Cheng 		if (attrp->va_link_id == DATALINK_INVALID_LINKID) {
2258275SEric Cheng 			status = DLADM_STATUS_BADARG;
2268275SEric Cheng 			goto done;
2278275SEric Cheng 		}
2288275SEric Cheng 		attrp->va_mac_addr_type = VNIC_MAC_ADDR_TYPE_PRIMARY;
2298275SEric Cheng 		attrp->va_mac_len = 0;
2308275SEric Cheng 	} else {
2318453SAnurag.Maskey@Sun.COM 		status = dladm_get_conf_field(handle, conf, FMADDRTYPE, &u64,
2328275SEric Cheng 		    sizeof (u64));
2338275SEric Cheng 		if (status != DLADM_STATUS_OK)
2348275SEric Cheng 			goto done;
2358275SEric Cheng 
2368275SEric Cheng 		attrp->va_mac_addr_type = (vnic_mac_addr_type_t)u64;
2378275SEric Cheng 
23811076SCathy.Zhou@Sun.COM 		if ((status = dladm_get_conf_field(handle, conf, FVRID,
23911076SCathy.Zhou@Sun.COM 		    &u64, sizeof (u64))) != DLADM_STATUS_OK) {
24011076SCathy.Zhou@Sun.COM 			attrp->va_vrid = VRRP_VRID_NONE;
24111076SCathy.Zhou@Sun.COM 		} else {
24211076SCathy.Zhou@Sun.COM 			attrp->va_vrid = (vrid_t)u64;
24311076SCathy.Zhou@Sun.COM 		}
24411076SCathy.Zhou@Sun.COM 
24511076SCathy.Zhou@Sun.COM 		if ((status = dladm_get_conf_field(handle, conf, FVRAF,
24611076SCathy.Zhou@Sun.COM 		    &u64, sizeof (u64))) != DLADM_STATUS_OK) {
24711076SCathy.Zhou@Sun.COM 			attrp->va_af = AF_UNSPEC;
24811076SCathy.Zhou@Sun.COM 		} else {
24911076SCathy.Zhou@Sun.COM 			attrp->va_af = (int)u64;
25011076SCathy.Zhou@Sun.COM 		}
25111076SCathy.Zhou@Sun.COM 
2528453SAnurag.Maskey@Sun.COM 		status = dladm_get_conf_field(handle, conf, FMADDRLEN, &u64,
2538275SEric Cheng 		    sizeof (u64));
2548275SEric Cheng 		attrp->va_mac_len = ((status == DLADM_STATUS_OK) ?
2558275SEric Cheng 		    (uint_t)u64 : ETHERADDRL);
2568275SEric Cheng 
2578453SAnurag.Maskey@Sun.COM 		status = dladm_get_conf_field(handle, conf, FMADDRSLOT, &u64,
2588275SEric Cheng 		    sizeof (u64));
2598275SEric Cheng 		attrp->va_mac_slot = ((status == DLADM_STATUS_OK) ?
2608275SEric Cheng 		    (int)u64 : -1);
2618275SEric Cheng 
2628453SAnurag.Maskey@Sun.COM 		status = dladm_get_conf_field(handle, conf, FMADDRPREFIXLEN,
2638453SAnurag.Maskey@Sun.COM 		    &u64, sizeof (u64));
2648275SEric Cheng 		attrp->va_mac_prefix_len = ((status == DLADM_STATUS_OK) ?
2658275SEric Cheng 		    (uint_t)u64 : sizeof (dladm_vnic_def_prefix));
2668275SEric Cheng 
2678453SAnurag.Maskey@Sun.COM 		status = dladm_get_conf_field(handle, conf, FMACADDR, macstr,
2688275SEric Cheng 		    sizeof (macstr));
2698275SEric Cheng 		if (status != DLADM_STATUS_OK)
2708275SEric Cheng 			goto done;
2718275SEric Cheng 
2728275SEric Cheng 		status = dladm_vnic_str2macaddr(macstr, attrp->va_mac_addr);
2738275SEric Cheng 		if (status != DLADM_STATUS_OK)
2748275SEric Cheng 			goto done;
2758275SEric Cheng 	}
2768275SEric Cheng 
2778453SAnurag.Maskey@Sun.COM 	status = dladm_get_conf_field(handle, conf, FVLANID, &u64,
2788453SAnurag.Maskey@Sun.COM 	    sizeof (u64));
2798275SEric Cheng 	attrp->va_vid = ((status == DLADM_STATUS_OK) ?  (uint16_t)u64 : 0);
2808275SEric Cheng 
2818275SEric Cheng 	status = DLADM_STATUS_OK;
2828275SEric Cheng done:
2838453SAnurag.Maskey@Sun.COM 	dladm_destroy_conf(handle, conf);
2848275SEric Cheng 	return (status);
2858275SEric Cheng }
2868275SEric Cheng 
2878275SEric Cheng dladm_status_t
2888453SAnurag.Maskey@Sun.COM dladm_vnic_info(dladm_handle_t handle, datalink_id_t linkid,
2898453SAnurag.Maskey@Sun.COM     dladm_vnic_attr_t *attrp, uint32_t flags)
2908275SEric Cheng {
2918275SEric Cheng 	if (flags == DLADM_OPT_ACTIVE)
2928453SAnurag.Maskey@Sun.COM 		return (i_dladm_vnic_info_active(handle, linkid, attrp));
2938275SEric Cheng 	else if (flags == DLADM_OPT_PERSIST)
2948453SAnurag.Maskey@Sun.COM 		return (i_dladm_vnic_info_persist(handle, linkid, attrp));
2958275SEric Cheng 	else
2968275SEric Cheng 		return (DLADM_STATUS_BADARG);
2978275SEric Cheng }
2988275SEric Cheng 
2998275SEric Cheng /*
3008275SEric Cheng  * Remove a VNIC from the kernel.
3018275SEric Cheng  */
3028275SEric Cheng dladm_status_t
3038453SAnurag.Maskey@Sun.COM i_dladm_vnic_delete_sys(dladm_handle_t handle, datalink_id_t linkid)
3048275SEric Cheng {
3058275SEric Cheng 	vnic_ioc_delete_t ioc;
3068275SEric Cheng 	dladm_status_t status = DLADM_STATUS_OK;
3078453SAnurag.Maskey@Sun.COM 	int rc;
3088275SEric Cheng 
3098275SEric Cheng 	ioc.vd_vnic_id = linkid;
3108275SEric Cheng 
3118453SAnurag.Maskey@Sun.COM 	rc = ioctl(dladm_dld_fd(handle), VNIC_IOC_DELETE, &ioc);
3128275SEric Cheng 	if (rc < 0)
3137408SSebastien.Roy@Sun.COM 		status = dladm_errno2status(errno);
3145084Sjohnlev 
3157408SSebastien.Roy@Sun.COM 	return (status);
3165084Sjohnlev }
3175084Sjohnlev 
3185084Sjohnlev /*
3195084Sjohnlev  * Convert between MAC address types and their string representations.
3205084Sjohnlev  */
3215084Sjohnlev 
3225084Sjohnlev typedef struct dladm_vnic_addr_type_s {
3238275SEric Cheng 	const char		*va_str;
3248275SEric Cheng 	vnic_mac_addr_type_t	va_type;
3255084Sjohnlev } dladm_vnic_addr_type_t;
3265084Sjohnlev 
3275084Sjohnlev static dladm_vnic_addr_type_t addr_types[] = {
3285084Sjohnlev 	{"fixed", VNIC_MAC_ADDR_TYPE_FIXED},
3298275SEric Cheng 	{"random", VNIC_MAC_ADDR_TYPE_RANDOM},
3308275SEric Cheng 	{"factory", VNIC_MAC_ADDR_TYPE_FACTORY},
3318275SEric Cheng 	{"auto", VNIC_MAC_ADDR_TYPE_AUTO},
33211076SCathy.Zhou@Sun.COM 	{"fixed", VNIC_MAC_ADDR_TYPE_PRIMARY},
33311076SCathy.Zhou@Sun.COM 	{"vrrp", VNIC_MAC_ADDR_TYPE_VRID}
3345084Sjohnlev };
3355084Sjohnlev 
3365084Sjohnlev #define	NADDR_TYPES (sizeof (addr_types) / sizeof (dladm_vnic_addr_type_t))
3375084Sjohnlev 
3388275SEric Cheng static const char *
3398275SEric Cheng dladm_vnic_macaddrtype2str(vnic_mac_addr_type_t type)
3408275SEric Cheng {
3418275SEric Cheng 	int i;
3428275SEric Cheng 
3438275SEric Cheng 	for (i = 0; i < NADDR_TYPES; i++) {
3448275SEric Cheng 		if (type == addr_types[i].va_type)
3458275SEric Cheng 			return (addr_types[i].va_str);
3468275SEric Cheng 	}
3478275SEric Cheng 	return (NULL);
3488275SEric Cheng }
3498275SEric Cheng 
3505895Syz147064 dladm_status_t
3515895Syz147064 dladm_vnic_str2macaddrtype(const char *str, vnic_mac_addr_type_t *val)
3525084Sjohnlev {
3535084Sjohnlev 	int i;
3545084Sjohnlev 	dladm_vnic_addr_type_t *type;
3555084Sjohnlev 
3565084Sjohnlev 	for (i = 0; i < NADDR_TYPES; i++) {
3575084Sjohnlev 		type = &addr_types[i];
3585084Sjohnlev 		if (strncmp(str, type->va_str, strlen(type->va_str)) == 0) {
3595084Sjohnlev 			*val = type->va_type;
3605895Syz147064 			return (DLADM_STATUS_OK);
3615084Sjohnlev 		}
3625084Sjohnlev 	}
3635895Syz147064 	return (DLADM_STATUS_BADARG);
3645084Sjohnlev }
3655084Sjohnlev 
3665084Sjohnlev /*
36711076SCathy.Zhou@Sun.COM  * Based on the VRRP specification, the virtual router MAC address associated
36811076SCathy.Zhou@Sun.COM  * with a virtual router is an IEEE 802 MAC address in the following format:
36911076SCathy.Zhou@Sun.COM  *
37011076SCathy.Zhou@Sun.COM  * IPv4 case: 00-00-5E-00-01-{VRID} (in hex in internet standard bit-order)
37111076SCathy.Zhou@Sun.COM  *
37211076SCathy.Zhou@Sun.COM  * IPv6 case: 00-00-5E-00-02-{VRID} (in hex in internet standard bit-order)
37311076SCathy.Zhou@Sun.COM  */
37411076SCathy.Zhou@Sun.COM static dladm_status_t
37511076SCathy.Zhou@Sun.COM i_dladm_vnic_vrrp_mac(vrid_t vrid, int af, uint8_t *mac, uint_t maclen)
37611076SCathy.Zhou@Sun.COM {
37711076SCathy.Zhou@Sun.COM 	if (maclen < ETHERADDRL || vrid < VRRP_VRID_MIN ||
37811076SCathy.Zhou@Sun.COM 	    vrid > VRRP_VRID_MAX || (af != AF_INET && af != AF_INET6)) {
37911076SCathy.Zhou@Sun.COM 		return (DLADM_STATUS_BADARG);
38011076SCathy.Zhou@Sun.COM 	}
38111076SCathy.Zhou@Sun.COM 
38211076SCathy.Zhou@Sun.COM 	mac[0] = mac[1] = mac[3] = 0x0;
38311076SCathy.Zhou@Sun.COM 	mac[2] = 0x5e;
38411076SCathy.Zhou@Sun.COM 	mac[4] = (af == AF_INET) ? 0x01 : 0x02;
38511076SCathy.Zhou@Sun.COM 	mac[5] = vrid;
38611076SCathy.Zhou@Sun.COM 	return (DLADM_STATUS_OK);
38711076SCathy.Zhou@Sun.COM }
38811076SCathy.Zhou@Sun.COM 
38911076SCathy.Zhou@Sun.COM /*
3908275SEric Cheng  * Create a new VNIC / VLAN. Update the configuration file and bring it up.
39111076SCathy.Zhou@Sun.COM  * The "vrid" and "af" arguments are only required if the mac_addr_type is
39211076SCathy.Zhou@Sun.COM  * VNIC_MAC_ADDR_TYPE_VRID. In that case, the MAC address will be caculated
39311076SCathy.Zhou@Sun.COM  * based on the above algorithm.
3945084Sjohnlev  */
3955084Sjohnlev dladm_status_t
3968453SAnurag.Maskey@Sun.COM dladm_vnic_create(dladm_handle_t handle, const char *vnic, datalink_id_t linkid,
39711076SCathy.Zhou@Sun.COM     vnic_mac_addr_type_t mac_addr_type, uchar_t *mac_addr, uint_t mac_len,
39811076SCathy.Zhou@Sun.COM     int *mac_slot, uint_t mac_prefix_len, uint16_t vid, vrid_t vrid,
39911076SCathy.Zhou@Sun.COM     int af, datalink_id_t *vnic_id_out, dladm_arg_list_t *proplist,
40011076SCathy.Zhou@Sun.COM     uint32_t flags)
4015084Sjohnlev {
4028275SEric Cheng 	dladm_vnic_attr_t attr;
4035895Syz147064 	datalink_id_t vnic_id;
4045895Syz147064 	datalink_class_t class;
4058275SEric Cheng 	uint32_t media = DL_ETHER;
4068275SEric Cheng 	char name[MAXLINKNAMELEN];
4078275SEric Cheng 	uchar_t tmp_addr[MAXMACADDRLEN];
4085084Sjohnlev 	dladm_status_t status;
4098275SEric Cheng 	boolean_t is_vlan;
4108275SEric Cheng 	boolean_t is_etherstub;
4118275SEric Cheng 	int i;
41210491SRishi.Srivatsavai@Sun.COM 	boolean_t vnic_created = B_FALSE;
41310491SRishi.Srivatsavai@Sun.COM 	boolean_t conf_set = B_FALSE;
4145084Sjohnlev 
4155084Sjohnlev 	/*
4165084Sjohnlev 	 * Sanity test arguments.
4175084Sjohnlev 	 */
4188275SEric Cheng 	if ((flags & DLADM_OPT_ACTIVE) == 0)
4198275SEric Cheng 		return (DLADM_STATUS_NOTSUP);
4208275SEric Cheng 
4218275SEric Cheng 	is_vlan = ((flags & DLADM_OPT_VLAN) != 0);
4228275SEric Cheng 	if (is_vlan && ((vid < 1 || vid > 4094)))
4238275SEric Cheng 		return (DLADM_STATUS_VIDINVAL);
4248275SEric Cheng 
4258275SEric Cheng 	is_etherstub = (linkid == DATALINK_INVALID_LINKID);
4265084Sjohnlev 
4278275SEric Cheng 	if (!dladm_vnic_macaddrtype2str(mac_addr_type))
4285084Sjohnlev 		return (DLADM_STATUS_INVALIDMACADDRTYPE);
4295084Sjohnlev 
43011076SCathy.Zhou@Sun.COM 	if ((flags & DLADM_OPT_ANCHOR) == 0) {
43111076SCathy.Zhou@Sun.COM 		if ((status = dladm_datalink_id2info(handle, linkid, NULL,
43211076SCathy.Zhou@Sun.COM 		    &class, &media, NULL, 0)) != DLADM_STATUS_OK)
43311076SCathy.Zhou@Sun.COM 			return (status);
43411076SCathy.Zhou@Sun.COM 
43511076SCathy.Zhou@Sun.COM 		if (class == DATALINK_CLASS_VNIC ||
43611076SCathy.Zhou@Sun.COM 		    class == DATALINK_CLASS_VLAN)
43711076SCathy.Zhou@Sun.COM 			return (DLADM_STATUS_BADARG);
43811076SCathy.Zhou@Sun.COM 	} else {
43911076SCathy.Zhou@Sun.COM 		/* it's an anchor VNIC */
44011076SCathy.Zhou@Sun.COM 		if (linkid != DATALINK_INVALID_LINKID || vid != 0)
44111076SCathy.Zhou@Sun.COM 			return (DLADM_STATUS_BADARG);
44211076SCathy.Zhou@Sun.COM 	}
44311076SCathy.Zhou@Sun.COM 
44411076SCathy.Zhou@Sun.COM 	/*
44511076SCathy.Zhou@Sun.COM 	 * Only VRRP VNIC need VRID and address family specified.
44611076SCathy.Zhou@Sun.COM 	 */
44711076SCathy.Zhou@Sun.COM 	if (mac_addr_type != VNIC_MAC_ADDR_TYPE_VRID &&
44811076SCathy.Zhou@Sun.COM 	    (af != AF_UNSPEC || vrid != VRRP_VRID_NONE)) {
44911076SCathy.Zhou@Sun.COM 		return (DLADM_STATUS_BADARG);
45011076SCathy.Zhou@Sun.COM 	}
45111076SCathy.Zhou@Sun.COM 
4528275SEric Cheng 	/*
4538275SEric Cheng 	 * If a random address might be generated, but no prefix
4548275SEric Cheng 	 * was specified by the caller, use the default MAC address
4558275SEric Cheng 	 * prefix.
4568275SEric Cheng 	 */
4578275SEric Cheng 	if ((mac_addr_type == VNIC_MAC_ADDR_TYPE_RANDOM ||
4588275SEric Cheng 	    mac_addr_type == VNIC_MAC_ADDR_TYPE_AUTO) &&
4598275SEric Cheng 	    mac_prefix_len == 0) {
4608275SEric Cheng 		mac_prefix_len = sizeof (dladm_vnic_def_prefix);
4618275SEric Cheng 		mac_addr = tmp_addr;
4628275SEric Cheng 		bcopy(dladm_vnic_def_prefix, mac_addr, mac_prefix_len);
4635895Syz147064 	}
4645895Syz147064 
46511076SCathy.Zhou@Sun.COM 	/*
46611076SCathy.Zhou@Sun.COM 	 * If this is a VRRP VNIC, generate its MAC address using the given
46711076SCathy.Zhou@Sun.COM 	 * VRID and address family.
46811076SCathy.Zhou@Sun.COM 	 */
46911076SCathy.Zhou@Sun.COM 	if (mac_addr_type == VNIC_MAC_ADDR_TYPE_VRID) {
47011076SCathy.Zhou@Sun.COM 		/*
47111076SCathy.Zhou@Sun.COM 		 * VRRP VNICs must be created over ethernet data-links.
47211076SCathy.Zhou@Sun.COM 		 */
47311076SCathy.Zhou@Sun.COM 		if (vrid < VRRP_VRID_MIN || vrid > VRRP_VRID_MAX ||
47411076SCathy.Zhou@Sun.COM 		    (af != AF_INET && af != AF_INET6) || mac_addr != NULL ||
47511076SCathy.Zhou@Sun.COM 		    mac_len != 0 || mac_prefix_len != 0 ||
47611076SCathy.Zhou@Sun.COM 		    (mac_slot != NULL && *mac_slot != -1) || is_etherstub ||
47711076SCathy.Zhou@Sun.COM 		    media != DL_ETHER) {
47811076SCathy.Zhou@Sun.COM 			return (DLADM_STATUS_BADARG);
47911076SCathy.Zhou@Sun.COM 		}
48011076SCathy.Zhou@Sun.COM 		mac_len = ETHERADDRL;
48111076SCathy.Zhou@Sun.COM 		mac_addr = tmp_addr;
48211076SCathy.Zhou@Sun.COM 		status = i_dladm_vnic_vrrp_mac(vrid, af, mac_addr, mac_len);
48311076SCathy.Zhou@Sun.COM 		if (status != DLADM_STATUS_OK)
4848275SEric Cheng 			return (status);
48511076SCathy.Zhou@Sun.COM 	}
4868275SEric Cheng 
48711076SCathy.Zhou@Sun.COM 	if (mac_len > MAXMACADDRLEN)
48811076SCathy.Zhou@Sun.COM 		return (DLADM_STATUS_INVALIDMACADDRLEN);
4895084Sjohnlev 
4905895Syz147064 	if (vnic == NULL) {
4915895Syz147064 		flags |= DLADM_OPT_PREFIX;
4928275SEric Cheng 		(void) strlcpy(name, "vnic", sizeof (name));
4938275SEric Cheng 	} else {
4948275SEric Cheng 		(void) strlcpy(name, vnic, sizeof (name));
4955895Syz147064 	}
4965895Syz147064 
4978275SEric Cheng 	class = is_vlan ? DATALINK_CLASS_VLAN :
4988275SEric Cheng 	    (is_etherstub ? DATALINK_CLASS_ETHERSTUB : DATALINK_CLASS_VNIC);
4998453SAnurag.Maskey@Sun.COM 	if ((status = dladm_create_datalink_id(handle, name, class,
5008275SEric Cheng 	    media, flags, &vnic_id)) != DLADM_STATUS_OK)
5015895Syz147064 		return (status);
5028275SEric Cheng 
5038275SEric Cheng 	if ((flags & DLADM_OPT_PREFIX) != 0) {
5048275SEric Cheng 		(void) snprintf(name + 4, sizeof (name), "%llu", vnic_id);
5058275SEric Cheng 		flags &= ~DLADM_OPT_PREFIX;
5065084Sjohnlev 	}
5075084Sjohnlev 
5085084Sjohnlev 	bzero(&attr, sizeof (attr));
5098275SEric Cheng 
5108275SEric Cheng 	/* Extract resource_ctl and cpu_list from proplist */
5118275SEric Cheng 	if (proplist != NULL) {
5128453SAnurag.Maskey@Sun.COM 		status = dladm_link_proplist_extract(handle, proplist,
51311878SVenu.Iyer@Sun.COM 		    &attr.va_resource_props, 0);
5148275SEric Cheng 		if (status != DLADM_STATUS_OK)
5158275SEric Cheng 			goto done;
5168275SEric Cheng 	}
5175084Sjohnlev 
5188275SEric Cheng 	attr.va_vnic_id = vnic_id;
5198275SEric Cheng 	attr.va_link_id = linkid;
5208275SEric Cheng 	attr.va_mac_addr_type = mac_addr_type;
5218275SEric Cheng 	attr.va_mac_len = mac_len;
5228275SEric Cheng 	if (mac_slot != NULL)
5238275SEric Cheng 		attr.va_mac_slot = *mac_slot;
5248275SEric Cheng 	if (mac_len > 0)
5258275SEric Cheng 		bcopy(mac_addr, attr.va_mac_addr, mac_len);
5268275SEric Cheng 	else if (mac_prefix_len > 0)
5278275SEric Cheng 		bcopy(mac_addr, attr.va_mac_addr, mac_prefix_len);
5288275SEric Cheng 	attr.va_mac_prefix_len = mac_prefix_len;
5298275SEric Cheng 	attr.va_vid = vid;
53011076SCathy.Zhou@Sun.COM 	attr.va_vrid = vrid;
53111076SCathy.Zhou@Sun.COM 	attr.va_af = af;
5328275SEric Cheng 	attr.va_force = (flags & DLADM_OPT_FORCE) != 0;
5338275SEric Cheng 
5348453SAnurag.Maskey@Sun.COM 	status = i_dladm_vnic_create_sys(handle, &attr);
5358275SEric Cheng 	if (status != DLADM_STATUS_OK)
5368275SEric Cheng 		goto done;
53710491SRishi.Srivatsavai@Sun.COM 	vnic_created = B_TRUE;
5388275SEric Cheng 
5398275SEric Cheng 	/* Save vnic configuration and its properties */
5408275SEric Cheng 	if (!(flags & DLADM_OPT_PERSIST))
5418275SEric Cheng 		goto done;
5428275SEric Cheng 
5438453SAnurag.Maskey@Sun.COM 	status = dladm_vnic_persist_conf(handle, name, &attr, class);
54410491SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK)
5455895Syz147064 		goto done;
54610491SRishi.Srivatsavai@Sun.COM 	conf_set = B_TRUE;
5475895Syz147064 
5488275SEric Cheng 	if (proplist != NULL) {
5498275SEric Cheng 		for (i = 0; i < proplist->al_count; i++) {
5508275SEric Cheng 			dladm_arg_info_t	*aip = &proplist->al_info[i];
5518275SEric Cheng 
5528453SAnurag.Maskey@Sun.COM 			status = dladm_set_linkprop(handle, vnic_id,
5538453SAnurag.Maskey@Sun.COM 			    aip->ai_name, aip->ai_val, aip->ai_count,
5548453SAnurag.Maskey@Sun.COM 			    DLADM_OPT_PERSIST);
5558275SEric Cheng 			if (status != DLADM_STATUS_OK)
5568275SEric Cheng 				break;
5578275SEric Cheng 		}
5588275SEric Cheng 	}
5595084Sjohnlev 
5605895Syz147064 done:
5615895Syz147064 	if (status != DLADM_STATUS_OK) {
56210491SRishi.Srivatsavai@Sun.COM 		if (conf_set)
56310491SRishi.Srivatsavai@Sun.COM 			(void) dladm_remove_conf(handle, vnic_id);
56410491SRishi.Srivatsavai@Sun.COM 		if (vnic_created)
56510491SRishi.Srivatsavai@Sun.COM 			(void) i_dladm_vnic_delete_sys(handle, vnic_id);
5668453SAnurag.Maskey@Sun.COM 		(void) dladm_destroy_datalink_id(handle, vnic_id, flags);
5675895Syz147064 	} else {
5688275SEric Cheng 		if (vnic_id_out != NULL)
5698275SEric Cheng 			*vnic_id_out = vnic_id;
5708275SEric Cheng 		if (mac_slot != NULL)
5718275SEric Cheng 			*mac_slot = attr.va_mac_slot;
5725895Syz147064 	}
57310491SRishi.Srivatsavai@Sun.COM 
57410491SRishi.Srivatsavai@Sun.COM 	if (is_vlan) {
57510491SRishi.Srivatsavai@Sun.COM 		dladm_status_t stat2;
57610491SRishi.Srivatsavai@Sun.COM 
57710491SRishi.Srivatsavai@Sun.COM 		stat2 = dladm_bridge_refresh(handle, linkid);
57810491SRishi.Srivatsavai@Sun.COM 		if (status == DLADM_STATUS_OK && stat2 != DLADM_STATUS_OK)
57910491SRishi.Srivatsavai@Sun.COM 			status = stat2;
58010491SRishi.Srivatsavai@Sun.COM 	}
5815084Sjohnlev 	return (status);
5825084Sjohnlev }
5835084Sjohnlev 
5845084Sjohnlev /*
5858275SEric Cheng  * Delete a VNIC / VLAN.
5865084Sjohnlev  */
5875084Sjohnlev dladm_status_t
5888453SAnurag.Maskey@Sun.COM dladm_vnic_delete(dladm_handle_t handle, datalink_id_t linkid, uint32_t flags)
5895084Sjohnlev {
5908275SEric Cheng 	dladm_status_t status;
5918275SEric Cheng 	datalink_class_t class;
5928275SEric Cheng 
5938275SEric Cheng 	if (flags == 0)
5948275SEric Cheng 		return (DLADM_STATUS_BADARG);
5955084Sjohnlev 
5968453SAnurag.Maskey@Sun.COM 	if ((dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, NULL, 0)
5978453SAnurag.Maskey@Sun.COM 	    != DLADM_STATUS_OK))
5988275SEric Cheng 		return (DLADM_STATUS_BADARG);
5995084Sjohnlev 
6008275SEric Cheng 	if ((flags & DLADM_OPT_VLAN) != 0) {
6018275SEric Cheng 		if (class != DATALINK_CLASS_VLAN)
6028275SEric Cheng 			return (DLADM_STATUS_BADARG);
6038275SEric Cheng 	} else {
6048275SEric Cheng 		if (class != DATALINK_CLASS_VNIC &&
6058275SEric Cheng 		    class != DATALINK_CLASS_ETHERSTUB)
6068275SEric Cheng 			return (DLADM_STATUS_BADARG);
6075084Sjohnlev 	}
6085084Sjohnlev 
6098275SEric Cheng 	if ((flags & DLADM_OPT_ACTIVE) != 0) {
6108453SAnurag.Maskey@Sun.COM 		status = i_dladm_vnic_delete_sys(handle, linkid);
6118275SEric Cheng 		if (status == DLADM_STATUS_OK) {
6128453SAnurag.Maskey@Sun.COM 			(void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0,
6138275SEric Cheng 			    DLADM_OPT_ACTIVE);
6148453SAnurag.Maskey@Sun.COM 			(void) dladm_destroy_datalink_id(handle, linkid,
6158275SEric Cheng 			    DLADM_OPT_ACTIVE);
6168275SEric Cheng 		} else if (status != DLADM_STATUS_NOTFOUND ||
6178275SEric Cheng 		    !(flags & DLADM_OPT_PERSIST)) {
6188275SEric Cheng 			return (status);
6198275SEric Cheng 		}
6208275SEric Cheng 	}
6218275SEric Cheng 	if ((flags & DLADM_OPT_PERSIST) != 0) {
62210616SSebastien.Roy@Sun.COM 		(void) dladm_remove_conf(handle, linkid);
6238453SAnurag.Maskey@Sun.COM 		(void) dladm_destroy_datalink_id(handle, linkid,
6248453SAnurag.Maskey@Sun.COM 		    DLADM_OPT_PERSIST);
6258275SEric Cheng 	}
62610491SRishi.Srivatsavai@Sun.COM 	return (dladm_bridge_refresh(handle, linkid));
6278275SEric Cheng }
6288275SEric Cheng 
6298275SEric Cheng static const char *
6308275SEric Cheng dladm_vnic_macaddr2str(const uchar_t *mac, char *buf)
6318275SEric Cheng {
6328275SEric Cheng 	static char unknown_mac[] = {0, 0, 0, 0, 0, 0};
6338275SEric Cheng 
6348275SEric Cheng 	if (buf == NULL)
6358275SEric Cheng 		return (NULL);
6368275SEric Cheng 
6378275SEric Cheng 	if (bcmp(unknown_mac, mac, ETHERADDRL) == 0)
6388275SEric Cheng 		(void) strlcpy(buf, "unknown", DLADM_STRSIZE);
6398275SEric Cheng 	else
6408275SEric Cheng 		return (_link_ntoa(mac, buf, ETHERADDRL, IFT_OTHER));
6418275SEric Cheng 
6428275SEric Cheng 	return (buf);
6438275SEric Cheng }
6448275SEric Cheng 
6458275SEric Cheng static dladm_status_t
6468275SEric Cheng dladm_vnic_str2macaddr(const char *str, uchar_t *buf)
6478275SEric Cheng {
6488275SEric Cheng 	int len = 0;
6498275SEric Cheng 	uchar_t *b = _link_aton(str, &len);
6508275SEric Cheng 
6518275SEric Cheng 	if (b == NULL || len >= MAXMACADDRLEN)
6528275SEric Cheng 		return (DLADM_STATUS_BADARG);
6538275SEric Cheng 
6548275SEric Cheng 	bcopy(b, buf, len);
6558275SEric Cheng 	free(b);
6568275SEric Cheng 	return (DLADM_STATUS_OK);
6575084Sjohnlev }
6585084Sjohnlev 
6595084Sjohnlev 
6608275SEric Cheng static dladm_status_t
6618453SAnurag.Maskey@Sun.COM dladm_vnic_persist_conf(dladm_handle_t handle, const char *name,
6628453SAnurag.Maskey@Sun.COM     dladm_vnic_attr_t *attrp, datalink_class_t class)
6638275SEric Cheng {
664*12824SCathy.Zhou@Sun.COM 	dladm_conf_t conf;
6658275SEric Cheng 	dladm_status_t status;
6668275SEric Cheng 	char macstr[ETHERADDRL * 3];
66710616SSebastien.Roy@Sun.COM 	char linkover[MAXLINKNAMELEN];
6688275SEric Cheng 	uint64_t u64;
6695084Sjohnlev 
6708453SAnurag.Maskey@Sun.COM 	if ((status = dladm_create_conf(handle, name, attrp->va_vnic_id,
6718275SEric Cheng 	    class, DL_ETHER, &conf)) != DLADM_STATUS_OK)
6725895Syz147064 		return (status);
6735895Syz147064 
6748275SEric Cheng 	if (attrp->va_link_id != DATALINK_INVALID_LINKID) {
67510616SSebastien.Roy@Sun.COM 		status = dladm_datalink_id2info(handle, attrp->va_link_id, NULL,
67610616SSebastien.Roy@Sun.COM 		    NULL, NULL, linkover, sizeof (linkover));
67710616SSebastien.Roy@Sun.COM 		if (status != DLADM_STATUS_OK)
67810616SSebastien.Roy@Sun.COM 			goto done;
6798453SAnurag.Maskey@Sun.COM 		status = dladm_set_conf_field(handle, conf, FLINKOVER,
68010616SSebastien.Roy@Sun.COM 		    DLADM_TYPE_STR, linkover);
6818275SEric Cheng 		if (status != DLADM_STATUS_OK)
6828275SEric Cheng 			goto done;
6838275SEric Cheng 	}
6848275SEric Cheng 
6858275SEric Cheng 	if (class != DATALINK_CLASS_VLAN) {
6868275SEric Cheng 		u64 = attrp->va_mac_addr_type;
6878453SAnurag.Maskey@Sun.COM 		status = dladm_set_conf_field(handle, conf, FMADDRTYPE,
6888275SEric Cheng 		    DLADM_TYPE_UINT64, &u64);
6898275SEric Cheng 		if (status != DLADM_STATUS_OK)
6908275SEric Cheng 			goto done;
6918275SEric Cheng 
69211076SCathy.Zhou@Sun.COM 		u64 = attrp->va_vrid;
69311076SCathy.Zhou@Sun.COM 		status = dladm_set_conf_field(handle, conf, FVRID,
69411076SCathy.Zhou@Sun.COM 		    DLADM_TYPE_UINT64, &u64);
69511076SCathy.Zhou@Sun.COM 		if (status != DLADM_STATUS_OK)
69611076SCathy.Zhou@Sun.COM 			goto done;
69711076SCathy.Zhou@Sun.COM 
69811076SCathy.Zhou@Sun.COM 		u64 = attrp->va_af;
69911076SCathy.Zhou@Sun.COM 		status = dladm_set_conf_field(handle, conf, FVRAF,
70011076SCathy.Zhou@Sun.COM 		    DLADM_TYPE_UINT64, &u64);
70111076SCathy.Zhou@Sun.COM 		if (status != DLADM_STATUS_OK)
70211076SCathy.Zhou@Sun.COM 			goto done;
70311076SCathy.Zhou@Sun.COM 
7048275SEric Cheng 		if (attrp->va_mac_len != ETHERADDRL) {
7058275SEric Cheng 			u64 = attrp->va_mac_len;
7068453SAnurag.Maskey@Sun.COM 			status = dladm_set_conf_field(handle, conf, FMADDRLEN,
7078275SEric Cheng 			    DLADM_TYPE_UINT64, &u64);
7088275SEric Cheng 			if (status != DLADM_STATUS_OK)
7098275SEric Cheng 				goto done;
7108275SEric Cheng 		}
7118275SEric Cheng 
7128275SEric Cheng 		if (attrp->va_mac_slot != -1) {
7138275SEric Cheng 			u64 = attrp->va_mac_slot;
71411076SCathy.Zhou@Sun.COM 			status = dladm_set_conf_field(handle, conf,
71511076SCathy.Zhou@Sun.COM 			    FMADDRSLOT, DLADM_TYPE_UINT64, &u64);
7168275SEric Cheng 			if (status != DLADM_STATUS_OK)
7178275SEric Cheng 			goto done;
7188275SEric Cheng 		}
7198275SEric Cheng 
7208275SEric Cheng 		if (attrp->va_mac_prefix_len !=
7218275SEric Cheng 		    sizeof (dladm_vnic_def_prefix)) {
7228275SEric Cheng 			u64 = attrp->va_mac_prefix_len;
7238453SAnurag.Maskey@Sun.COM 			status = dladm_set_conf_field(handle, conf,
7248453SAnurag.Maskey@Sun.COM 			    FMADDRPREFIXLEN, DLADM_TYPE_UINT64, &u64);
7258275SEric Cheng 			if (status != DLADM_STATUS_OK)
7268275SEric Cheng 				goto done;
7278275SEric Cheng 		}
7288275SEric Cheng 
7298275SEric Cheng 		(void) dladm_vnic_macaddr2str(attrp->va_mac_addr, macstr);
7308453SAnurag.Maskey@Sun.COM 		status = dladm_set_conf_field(handle, conf, FMACADDR,
7318453SAnurag.Maskey@Sun.COM 		    DLADM_TYPE_STR, macstr);
7328275SEric Cheng 		if (status != DLADM_STATUS_OK)
7338275SEric Cheng 			goto done;
7348275SEric Cheng 	}
7358275SEric Cheng 
7368275SEric Cheng 	if (attrp->va_vid != 0) {
7378275SEric Cheng 		u64 = attrp->va_vid;
7388453SAnurag.Maskey@Sun.COM 		status = dladm_set_conf_field(handle, conf, FVLANID,
7398275SEric Cheng 		    DLADM_TYPE_UINT64, &u64);
7408275SEric Cheng 		if (status != DLADM_STATUS_OK)
7418275SEric Cheng 			goto done;
7428275SEric Cheng 	}
7438275SEric Cheng 
7448275SEric Cheng 	/*
7458275SEric Cheng 	 * Commit the link configuration.
7468275SEric Cheng 	 */
7478453SAnurag.Maskey@Sun.COM 	status = dladm_write_conf(handle, conf);
7488275SEric Cheng 
7498275SEric Cheng done:
7508453SAnurag.Maskey@Sun.COM 	dladm_destroy_conf(handle, conf);
7515895Syz147064 	return (status);
7525084Sjohnlev }
7538275SEric Cheng 
7548275SEric Cheng typedef struct dladm_vnic_up_arg_s {
7558275SEric Cheng 	uint32_t	flags;
7568275SEric Cheng 	dladm_status_t	status;
7578275SEric Cheng } dladm_vnic_up_arg_t;
7588275SEric Cheng 
7598275SEric Cheng static int
7608453SAnurag.Maskey@Sun.COM i_dladm_vnic_up(dladm_handle_t handle, datalink_id_t linkid, void *arg)
7618275SEric Cheng {
7628275SEric Cheng 	dladm_status_t *statusp = &(((dladm_vnic_up_arg_t *)arg)->status);
7638275SEric Cheng 	dladm_vnic_attr_t attr;
7648275SEric Cheng 	dladm_status_t status;
7658275SEric Cheng 	dladm_arg_list_t *proplist;
7668275SEric Cheng 
7678275SEric Cheng 	bzero(&attr, sizeof (attr));
7688275SEric Cheng 
7698453SAnurag.Maskey@Sun.COM 	status = dladm_vnic_info(handle, linkid, &attr, DLADM_OPT_PERSIST);
7708275SEric Cheng 	if (status != DLADM_STATUS_OK)
7718275SEric Cheng 		goto done;
7728275SEric Cheng 
7738275SEric Cheng 	/* Get all properties for this vnic */
7748453SAnurag.Maskey@Sun.COM 	status = dladm_link_get_proplist(handle, linkid, &proplist);
7758275SEric Cheng 	if (status != DLADM_STATUS_OK)
7768275SEric Cheng 		goto done;
7778275SEric Cheng 
7788275SEric Cheng 	if (proplist != NULL) {
7798453SAnurag.Maskey@Sun.COM 		status = dladm_link_proplist_extract(handle, proplist,
78011878SVenu.Iyer@Sun.COM 		    &attr.va_resource_props, DLADM_OPT_BOOT);
7818275SEric Cheng 	}
7828275SEric Cheng 
7838453SAnurag.Maskey@Sun.COM 	status = i_dladm_vnic_create_sys(handle, &attr);
78410491SRishi.Srivatsavai@Sun.COM 	if (status == DLADM_STATUS_OK) {
78510491SRishi.Srivatsavai@Sun.COM 		status = dladm_up_datalink_id(handle, linkid);
78610491SRishi.Srivatsavai@Sun.COM 		if (status != DLADM_STATUS_OK)
78710491SRishi.Srivatsavai@Sun.COM 			(void) i_dladm_vnic_delete_sys(handle, linkid);
78810491SRishi.Srivatsavai@Sun.COM 	}
7898275SEric Cheng 
7908275SEric Cheng done:
7918275SEric Cheng 	*statusp = status;
7928275SEric Cheng 	return (DLADM_WALK_CONTINUE);
7938275SEric Cheng }
7948275SEric Cheng 
7958275SEric Cheng dladm_status_t
7968453SAnurag.Maskey@Sun.COM dladm_vnic_up(dladm_handle_t handle, datalink_id_t linkid, uint32_t flags)
7978275SEric Cheng {
7988275SEric Cheng 	dladm_vnic_up_arg_t vnic_arg;
7998275SEric Cheng 	datalink_class_t class;
8008275SEric Cheng 
8018275SEric Cheng 	class = ((flags & DLADM_OPT_VLAN) != 0) ? DATALINK_CLASS_VLAN :
8028275SEric Cheng 	    (DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB);
8038275SEric Cheng 
8048275SEric Cheng 	if (linkid == DATALINK_ALL_LINKID) {
8058453SAnurag.Maskey@Sun.COM 		(void) dladm_walk_datalink_id(i_dladm_vnic_up, handle,
8068453SAnurag.Maskey@Sun.COM 		    &vnic_arg, class, DATALINK_ANY_MEDIATYPE,
8078453SAnurag.Maskey@Sun.COM 		    DLADM_OPT_PERSIST);
8088275SEric Cheng 		return (DLADM_STATUS_OK);
8098275SEric Cheng 	} else {
8108453SAnurag.Maskey@Sun.COM 		(void) i_dladm_vnic_up(handle, linkid, &vnic_arg);
8118275SEric Cheng 		return (vnic_arg.status);
8128275SEric Cheng 	}
8138275SEric Cheng }
814