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*11878SVenu.Iyer@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
235084Sjohnlev  * Use is subject to license terms.
245084Sjohnlev  */
255084Sjohnlev 
265084Sjohnlev #include <stdio.h>
275084Sjohnlev #include <sys/types.h>
285084Sjohnlev #include <sys/stat.h>
295084Sjohnlev #include <string.h>
305084Sjohnlev #include <fcntl.h>
315084Sjohnlev #include <unistd.h>
325084Sjohnlev #include <stropts.h>
335084Sjohnlev #include <stdlib.h>
345084Sjohnlev #include <errno.h>
355084Sjohnlev #include <strings.h>
365084Sjohnlev #include <libintl.h>
375084Sjohnlev #include <net/if_types.h>
385084Sjohnlev #include <net/if_dl.h>
398275SEric Cheng #include <sys/dld.h>
405084Sjohnlev #include <libdladm_impl.h>
4111076SCathy.Zhou@Sun.COM #include <libvrrpadm.h>
425895Syz147064 #include <libdllink.h>
4310491SRishi.Srivatsavai@Sun.COM #include <libdlbridge.h>
445084Sjohnlev #include <libdlvnic.h>
455084Sjohnlev 
465084Sjohnlev /*
475084Sjohnlev  * VNIC administration library.
485084Sjohnlev  */
495084Sjohnlev 
508275SEric Cheng /*
518275SEric Cheng  * Default random MAC address prefix (locally administered).
528275SEric Cheng  */
538275SEric Cheng static char dladm_vnic_def_prefix[] = {0x02, 0x08, 0x20};
548275SEric Cheng 
558453SAnurag.Maskey@Sun.COM static dladm_status_t	dladm_vnic_persist_conf(dladm_handle_t,
568453SAnurag.Maskey@Sun.COM 			    const char *name, dladm_vnic_attr_t *,
578453SAnurag.Maskey@Sun.COM 			    datalink_class_t);
588275SEric Cheng static const char	*dladm_vnic_macaddr2str(const uchar_t *, char *);
598275SEric Cheng static dladm_status_t	dladm_vnic_str2macaddr(const char *, uchar_t *);
605084Sjohnlev 
618275SEric Cheng /*
628275SEric Cheng  * Convert a diagnostic returned by the kernel into a dladm_status_t.
638275SEric Cheng  */
648275SEric Cheng static dladm_status_t
658275SEric Cheng dladm_vnic_diag2status(vnic_ioc_diag_t ioc_diag)
668275SEric Cheng {
678275SEric Cheng 	switch (ioc_diag) {
6811076SCathy.Zhou@Sun.COM 	case VNIC_IOC_DIAG_NONE:
6911076SCathy.Zhou@Sun.COM 		return (DLADM_STATUS_OK);
708275SEric Cheng 	case VNIC_IOC_DIAG_MACADDRLEN_INVALID:
718275SEric Cheng 		return (DLADM_STATUS_INVALIDMACADDRLEN);
728275SEric Cheng 	case VNIC_IOC_DIAG_MACADDR_NIC:
738275SEric Cheng 		return (DLADM_STATUS_INVALIDMACADDRNIC);
748275SEric Cheng 	case VNIC_IOC_DIAG_MACADDR_INUSE:
758275SEric Cheng 		return (DLADM_STATUS_INVALIDMACADDRINUSE);
768275SEric Cheng 	case VNIC_IOC_DIAG_MACFACTORYSLOTINVALID:
778275SEric Cheng 		return (DLADM_STATUS_MACFACTORYSLOTINVALID);
788275SEric Cheng 	case VNIC_IOC_DIAG_MACFACTORYSLOTUSED:
798275SEric Cheng 		return (DLADM_STATUS_MACFACTORYSLOTUSED);
808275SEric Cheng 	case VNIC_IOC_DIAG_MACFACTORYSLOTALLUSED:
818275SEric Cheng 		return (DLADM_STATUS_MACFACTORYSLOTALLUSED);
828275SEric Cheng 	case VNIC_IOC_DIAG_MACFACTORYNOTSUP:
838275SEric Cheng 		return (DLADM_STATUS_MACFACTORYNOTSUP);
848275SEric Cheng 	case VNIC_IOC_DIAG_MACPREFIX_INVALID:
858275SEric Cheng 		return (DLADM_STATUS_INVALIDMACPREFIX);
868275SEric Cheng 	case VNIC_IOC_DIAG_MACPREFIXLEN_INVALID:
878275SEric Cheng 		return (DLADM_STATUS_INVALIDMACPREFIXLEN);
888275SEric Cheng 	case VNIC_IOC_DIAG_MACMARGIN_INVALID:
898275SEric Cheng 		return (DLADM_STATUS_INVALID_MACMARGIN);
908275SEric Cheng 	case VNIC_IOC_DIAG_NO_HWRINGS:
918275SEric Cheng 		return (DLADM_STATUS_NO_HWRINGS);
9211076SCathy.Zhou@Sun.COM 	case VNIC_IOC_DIAG_MACADDR_INVALID:
9311076SCathy.Zhou@Sun.COM 		return (DLADM_STATUS_INVALIDMACADDR);
9411076SCathy.Zhou@Sun.COM 	default:
9511076SCathy.Zhou@Sun.COM 		return (DLADM_STATUS_FAILED);
968275SEric Cheng 	}
978275SEric Cheng }
985084Sjohnlev 
995084Sjohnlev /*
1005084Sjohnlev  * Send a create command to the VNIC driver.
1015084Sjohnlev  */
1028275SEric Cheng dladm_status_t
1038453SAnurag.Maskey@Sun.COM i_dladm_vnic_create_sys(dladm_handle_t handle, dladm_vnic_attr_t *attr)
1045084Sjohnlev {
1058453SAnurag.Maskey@Sun.COM 	int rc;
1065084Sjohnlev 	vnic_ioc_create_t ioc;
1078275SEric Cheng 	dladm_status_t status = DLADM_STATUS_OK;
1085084Sjohnlev 
1098275SEric Cheng 	bzero(&ioc, sizeof (ioc));
1108275SEric Cheng 	ioc.vc_vnic_id = attr->va_vnic_id;
1118275SEric Cheng 	ioc.vc_link_id = attr->va_link_id;
1128275SEric Cheng 	ioc.vc_mac_addr_type = attr->va_mac_addr_type;
1138275SEric Cheng 	ioc.vc_mac_len = attr->va_mac_len;
1148275SEric Cheng 	ioc.vc_mac_slot = attr->va_mac_slot;
1158275SEric Cheng 	ioc.vc_mac_prefix_len = attr->va_mac_prefix_len;
1168275SEric Cheng 	ioc.vc_vid = attr->va_vid;
11711076SCathy.Zhou@Sun.COM 	ioc.vc_vrid = attr->va_vrid;
11811076SCathy.Zhou@Sun.COM 	ioc.vc_af = attr->va_af;
1198275SEric Cheng 	ioc.vc_flags = attr->va_force ? VNIC_IOC_CREATE_FORCE : 0;
1205084Sjohnlev 
1218275SEric Cheng 	if (attr->va_mac_len > 0 || ioc.vc_mac_prefix_len > 0)
1228275SEric Cheng 		bcopy(attr->va_mac_addr, ioc.vc_mac_addr, MAXMACADDRLEN);
1238275SEric Cheng 	bcopy(&attr->va_resource_props, &ioc.vc_resource_props,
1248275SEric Cheng 	    sizeof (mac_resource_props_t));
1258275SEric Cheng 	if (attr->va_link_id == DATALINK_INVALID_LINKID)
1268275SEric Cheng 		ioc.vc_flags |= VNIC_IOC_CREATE_ANCHOR;
1275084Sjohnlev 
1288453SAnurag.Maskey@Sun.COM 	rc = ioctl(dladm_dld_fd(handle), VNIC_IOC_CREATE, &ioc);
1298275SEric Cheng 	if (rc < 0)
1308275SEric Cheng 		status = dladm_errno2status(errno);
1318275SEric Cheng 
1328275SEric Cheng 	if (status != DLADM_STATUS_OK) {
1338275SEric Cheng 		if (ioc.vc_diag != VNIC_IOC_DIAG_NONE)
1348275SEric Cheng 			status = dladm_vnic_diag2status(ioc.vc_diag);
1358275SEric Cheng 	}
1368275SEric Cheng 	if (status != DLADM_STATUS_OK)
1378275SEric Cheng 		return (status);
1388275SEric Cheng 
1398275SEric Cheng 	attr->va_mac_addr_type = ioc.vc_mac_addr_type;
1408275SEric Cheng 	switch (ioc.vc_mac_addr_type) {
1418275SEric Cheng 	case VNIC_MAC_ADDR_TYPE_FACTORY:
1428275SEric Cheng 		attr->va_mac_slot = ioc.vc_mac_slot;
1438275SEric Cheng 		break;
1448275SEric Cheng 	case VNIC_MAC_ADDR_TYPE_RANDOM:
1458275SEric Cheng 		bcopy(ioc.vc_mac_addr, attr->va_mac_addr, MAXMACADDRLEN);
1468275SEric Cheng 		attr->va_mac_len = ioc.vc_mac_len;
1478275SEric Cheng 		break;
1488275SEric Cheng 	}
1498275SEric Cheng 	return (status);
1508275SEric Cheng }
1518275SEric Cheng 
1528275SEric Cheng /*
1538275SEric Cheng  * Get the configuration information of the given VNIC.
1548275SEric Cheng  */
1558275SEric Cheng static dladm_status_t
1568453SAnurag.Maskey@Sun.COM i_dladm_vnic_info_active(dladm_handle_t handle, datalink_id_t linkid,
1578453SAnurag.Maskey@Sun.COM     dladm_vnic_attr_t *attrp)
1588275SEric Cheng {
1598275SEric Cheng 	vnic_ioc_info_t ioc;
1608275SEric Cheng 	vnic_info_t *vnic;
1618453SAnurag.Maskey@Sun.COM 	int rc;
1628275SEric Cheng 	dladm_status_t status = DLADM_STATUS_OK;
1638275SEric Cheng 
1648275SEric Cheng 	bzero(&ioc, sizeof (ioc));
1658275SEric Cheng 	vnic = &ioc.vi_info;
1668275SEric Cheng 	vnic->vn_vnic_id = linkid;
1678275SEric Cheng 
1688453SAnurag.Maskey@Sun.COM 	rc = ioctl(dladm_dld_fd(handle), VNIC_IOC_INFO, &ioc);
1698275SEric Cheng 	if (rc != 0) {
1708275SEric Cheng 		status = dladm_errno2status(errno);
1718275SEric Cheng 		goto bail;
1728275SEric Cheng 	}
1738275SEric Cheng 
1748275SEric Cheng 	attrp->va_vnic_id = vnic->vn_vnic_id;
1758275SEric Cheng 	attrp->va_link_id = vnic->vn_link_id;
1768275SEric Cheng 	attrp->va_mac_addr_type = vnic->vn_mac_addr_type;
1778275SEric Cheng 	bcopy(vnic->vn_mac_addr, attrp->va_mac_addr, MAXMACADDRLEN);
1788275SEric Cheng 	attrp->va_mac_len = vnic->vn_mac_len;
1798275SEric Cheng 	attrp->va_mac_slot = vnic->vn_mac_slot;
1808275SEric Cheng 	attrp->va_mac_prefix_len = vnic->vn_mac_prefix_len;
1818275SEric Cheng 	attrp->va_vid = vnic->vn_vid;
18211076SCathy.Zhou@Sun.COM 	attrp->va_vrid = vnic->vn_vrid;
18311076SCathy.Zhou@Sun.COM 	attrp->va_af = vnic->vn_af;
1848275SEric Cheng 	attrp->va_force = vnic->vn_force;
1858275SEric Cheng 
1868275SEric Cheng bail:
1878275SEric Cheng 	return (status);
1888275SEric Cheng }
1898275SEric Cheng 
1908275SEric Cheng static dladm_status_t
1918453SAnurag.Maskey@Sun.COM i_dladm_vnic_info_persist(dladm_handle_t handle, datalink_id_t linkid,
1928453SAnurag.Maskey@Sun.COM     dladm_vnic_attr_t *attrp)
1938275SEric Cheng {
1948275SEric Cheng 	dladm_conf_t conf;
1958275SEric Cheng 	dladm_status_t status;
1968275SEric Cheng 	char macstr[ETHERADDRL * 3];
19710616SSebastien.Roy@Sun.COM 	char linkover[MAXLINKNAMELEN];
1988275SEric Cheng 	uint64_t u64;
1998275SEric Cheng 	datalink_class_t class;
2008275SEric Cheng 
2018275SEric Cheng 	attrp->va_vnic_id = linkid;
2028453SAnurag.Maskey@Sun.COM 	if ((status = dladm_read_conf(handle, linkid, &conf)) !=
2038453SAnurag.Maskey@Sun.COM 	    DLADM_STATUS_OK)
2048275SEric Cheng 		return (status);
2058275SEric Cheng 
20610616SSebastien.Roy@Sun.COM 	status = dladm_get_conf_field(handle, conf, FLINKOVER, linkover,
20710616SSebastien.Roy@Sun.COM 	    sizeof (linkover));
20810616SSebastien.Roy@Sun.COM 	if (status != DLADM_STATUS_OK) {
20910616SSebastien.Roy@Sun.COM 		/*
21010616SSebastien.Roy@Sun.COM 		 * This isn't an error, etherstubs don't have a FLINKOVER
21110616SSebastien.Roy@Sun.COM 		 * property.
21210616SSebastien.Roy@Sun.COM 		 */
21310616SSebastien.Roy@Sun.COM 		attrp->va_link_id = DATALINK_INVALID_LINKID;
21410616SSebastien.Roy@Sun.COM 	} else {
21510616SSebastien.Roy@Sun.COM 		if ((status = dladm_name2info(handle, linkover,
21610616SSebastien.Roy@Sun.COM 		    &attrp->va_link_id, NULL, NULL, NULL)) != DLADM_STATUS_OK)
21710616SSebastien.Roy@Sun.COM 			goto done;
21810616SSebastien.Roy@Sun.COM 	}
2198275SEric Cheng 
2208453SAnurag.Maskey@Sun.COM 	if ((status = dladm_datalink_id2info(handle, linkid, NULL, &class,
2218275SEric Cheng 	    NULL, NULL, 0)) != DLADM_STATUS_OK)
2228275SEric Cheng 		goto done;
2238275SEric Cheng 
2248275SEric Cheng 	if (class == DATALINK_CLASS_VLAN) {
2258275SEric Cheng 		if (attrp->va_link_id == DATALINK_INVALID_LINKID) {
2268275SEric Cheng 			status = DLADM_STATUS_BADARG;
2278275SEric Cheng 			goto done;
2288275SEric Cheng 		}
2298275SEric Cheng 		attrp->va_mac_addr_type = VNIC_MAC_ADDR_TYPE_PRIMARY;
2308275SEric Cheng 		attrp->va_mac_len = 0;
2318275SEric Cheng 	} else {
2328453SAnurag.Maskey@Sun.COM 		status = dladm_get_conf_field(handle, conf, FMADDRTYPE, &u64,
2338275SEric Cheng 		    sizeof (u64));
2348275SEric Cheng 		if (status != DLADM_STATUS_OK)
2358275SEric Cheng 			goto done;
2368275SEric Cheng 
2378275SEric Cheng 		attrp->va_mac_addr_type = (vnic_mac_addr_type_t)u64;
2388275SEric Cheng 
23911076SCathy.Zhou@Sun.COM 		if ((status = dladm_get_conf_field(handle, conf, FVRID,
24011076SCathy.Zhou@Sun.COM 		    &u64, sizeof (u64))) != DLADM_STATUS_OK) {
24111076SCathy.Zhou@Sun.COM 			attrp->va_vrid = VRRP_VRID_NONE;
24211076SCathy.Zhou@Sun.COM 		} else {
24311076SCathy.Zhou@Sun.COM 			attrp->va_vrid = (vrid_t)u64;
24411076SCathy.Zhou@Sun.COM 		}
24511076SCathy.Zhou@Sun.COM 
24611076SCathy.Zhou@Sun.COM 		if ((status = dladm_get_conf_field(handle, conf, FVRAF,
24711076SCathy.Zhou@Sun.COM 		    &u64, sizeof (u64))) != DLADM_STATUS_OK) {
24811076SCathy.Zhou@Sun.COM 			attrp->va_af = AF_UNSPEC;
24911076SCathy.Zhou@Sun.COM 		} else {
25011076SCathy.Zhou@Sun.COM 			attrp->va_af = (int)u64;
25111076SCathy.Zhou@Sun.COM 		}
25211076SCathy.Zhou@Sun.COM 
2538453SAnurag.Maskey@Sun.COM 		status = dladm_get_conf_field(handle, conf, FMADDRLEN, &u64,
2548275SEric Cheng 		    sizeof (u64));
2558275SEric Cheng 		attrp->va_mac_len = ((status == DLADM_STATUS_OK) ?
2568275SEric Cheng 		    (uint_t)u64 : ETHERADDRL);
2578275SEric Cheng 
2588453SAnurag.Maskey@Sun.COM 		status = dladm_get_conf_field(handle, conf, FMADDRSLOT, &u64,
2598275SEric Cheng 		    sizeof (u64));
2608275SEric Cheng 		attrp->va_mac_slot = ((status == DLADM_STATUS_OK) ?
2618275SEric Cheng 		    (int)u64 : -1);
2628275SEric Cheng 
2638453SAnurag.Maskey@Sun.COM 		status = dladm_get_conf_field(handle, conf, FMADDRPREFIXLEN,
2648453SAnurag.Maskey@Sun.COM 		    &u64, sizeof (u64));
2658275SEric Cheng 		attrp->va_mac_prefix_len = ((status == DLADM_STATUS_OK) ?
2668275SEric Cheng 		    (uint_t)u64 : sizeof (dladm_vnic_def_prefix));
2678275SEric Cheng 
2688453SAnurag.Maskey@Sun.COM 		status = dladm_get_conf_field(handle, conf, FMACADDR, macstr,
2698275SEric Cheng 		    sizeof (macstr));
2708275SEric Cheng 		if (status != DLADM_STATUS_OK)
2718275SEric Cheng 			goto done;
2728275SEric Cheng 
2738275SEric Cheng 		status = dladm_vnic_str2macaddr(macstr, attrp->va_mac_addr);
2748275SEric Cheng 		if (status != DLADM_STATUS_OK)
2758275SEric Cheng 			goto done;
2768275SEric Cheng 	}
2778275SEric Cheng 
2788453SAnurag.Maskey@Sun.COM 	status = dladm_get_conf_field(handle, conf, FVLANID, &u64,
2798453SAnurag.Maskey@Sun.COM 	    sizeof (u64));
2808275SEric Cheng 	attrp->va_vid = ((status == DLADM_STATUS_OK) ?  (uint16_t)u64 : 0);
2818275SEric Cheng 
2828275SEric Cheng 
2838275SEric Cheng 	status = DLADM_STATUS_OK;
2848275SEric Cheng done:
2858453SAnurag.Maskey@Sun.COM 	dladm_destroy_conf(handle, conf);
2868275SEric Cheng 	return (status);
2878275SEric Cheng }
2888275SEric Cheng 
2898275SEric Cheng dladm_status_t
2908453SAnurag.Maskey@Sun.COM dladm_vnic_info(dladm_handle_t handle, datalink_id_t linkid,
2918453SAnurag.Maskey@Sun.COM     dladm_vnic_attr_t *attrp, uint32_t flags)
2928275SEric Cheng {
2938275SEric Cheng 	if (flags == DLADM_OPT_ACTIVE)
2948453SAnurag.Maskey@Sun.COM 		return (i_dladm_vnic_info_active(handle, linkid, attrp));
2958275SEric Cheng 	else if (flags == DLADM_OPT_PERSIST)
2968453SAnurag.Maskey@Sun.COM 		return (i_dladm_vnic_info_persist(handle, linkid, attrp));
2978275SEric Cheng 	else
2988275SEric Cheng 		return (DLADM_STATUS_BADARG);
2998275SEric Cheng }
3008275SEric Cheng 
3018275SEric Cheng /*
3028275SEric Cheng  * Remove a VNIC from the kernel.
3038275SEric Cheng  */
3048275SEric Cheng dladm_status_t
3058453SAnurag.Maskey@Sun.COM i_dladm_vnic_delete_sys(dladm_handle_t handle, datalink_id_t linkid)
3068275SEric Cheng {
3078275SEric Cheng 	vnic_ioc_delete_t ioc;
3088275SEric Cheng 	dladm_status_t status = DLADM_STATUS_OK;
3098453SAnurag.Maskey@Sun.COM 	int rc;
3108275SEric Cheng 
3118275SEric Cheng 	ioc.vd_vnic_id = linkid;
3128275SEric Cheng 
3138453SAnurag.Maskey@Sun.COM 	rc = ioctl(dladm_dld_fd(handle), VNIC_IOC_DELETE, &ioc);
3148275SEric Cheng 	if (rc < 0)
3157408SSebastien.Roy@Sun.COM 		status = dladm_errno2status(errno);
3165084Sjohnlev 
3177408SSebastien.Roy@Sun.COM 	return (status);
3185084Sjohnlev }
3195084Sjohnlev 
3205084Sjohnlev /*
3215084Sjohnlev  * Convert between MAC address types and their string representations.
3225084Sjohnlev  */
3235084Sjohnlev 
3245084Sjohnlev typedef struct dladm_vnic_addr_type_s {
3258275SEric Cheng 	const char		*va_str;
3268275SEric Cheng 	vnic_mac_addr_type_t	va_type;
3275084Sjohnlev } dladm_vnic_addr_type_t;
3285084Sjohnlev 
3295084Sjohnlev static dladm_vnic_addr_type_t addr_types[] = {
3305084Sjohnlev 	{"fixed", VNIC_MAC_ADDR_TYPE_FIXED},
3318275SEric Cheng 	{"random", VNIC_MAC_ADDR_TYPE_RANDOM},
3328275SEric Cheng 	{"factory", VNIC_MAC_ADDR_TYPE_FACTORY},
3338275SEric Cheng 	{"auto", VNIC_MAC_ADDR_TYPE_AUTO},
33411076SCathy.Zhou@Sun.COM 	{"fixed", VNIC_MAC_ADDR_TYPE_PRIMARY},
33511076SCathy.Zhou@Sun.COM 	{"vrrp", VNIC_MAC_ADDR_TYPE_VRID}
3365084Sjohnlev };
3375084Sjohnlev 
3385084Sjohnlev #define	NADDR_TYPES (sizeof (addr_types) / sizeof (dladm_vnic_addr_type_t))
3395084Sjohnlev 
3408275SEric Cheng static const char *
3418275SEric Cheng dladm_vnic_macaddrtype2str(vnic_mac_addr_type_t type)
3428275SEric Cheng {
3438275SEric Cheng 	int i;
3448275SEric Cheng 
3458275SEric Cheng 	for (i = 0; i < NADDR_TYPES; i++) {
3468275SEric Cheng 		if (type == addr_types[i].va_type)
3478275SEric Cheng 			return (addr_types[i].va_str);
3488275SEric Cheng 	}
3498275SEric Cheng 	return (NULL);
3508275SEric Cheng }
3518275SEric Cheng 
3525895Syz147064 dladm_status_t
3535895Syz147064 dladm_vnic_str2macaddrtype(const char *str, vnic_mac_addr_type_t *val)
3545084Sjohnlev {
3555084Sjohnlev 	int i;
3565084Sjohnlev 	dladm_vnic_addr_type_t *type;
3575084Sjohnlev 
3585084Sjohnlev 	for (i = 0; i < NADDR_TYPES; i++) {
3595084Sjohnlev 		type = &addr_types[i];
3605084Sjohnlev 		if (strncmp(str, type->va_str, strlen(type->va_str)) == 0) {
3615084Sjohnlev 			*val = type->va_type;
3625895Syz147064 			return (DLADM_STATUS_OK);
3635084Sjohnlev 		}
3645084Sjohnlev 	}
3655895Syz147064 	return (DLADM_STATUS_BADARG);
3665084Sjohnlev }
3675084Sjohnlev 
3685084Sjohnlev /*
36911076SCathy.Zhou@Sun.COM  * Based on the VRRP specification, the virtual router MAC address associated
37011076SCathy.Zhou@Sun.COM  * with a virtual router is an IEEE 802 MAC address in the following format:
37111076SCathy.Zhou@Sun.COM  *
37211076SCathy.Zhou@Sun.COM  * IPv4 case: 00-00-5E-00-01-{VRID} (in hex in internet standard bit-order)
37311076SCathy.Zhou@Sun.COM  *
37411076SCathy.Zhou@Sun.COM  * IPv6 case: 00-00-5E-00-02-{VRID} (in hex in internet standard bit-order)
37511076SCathy.Zhou@Sun.COM  */
37611076SCathy.Zhou@Sun.COM static dladm_status_t
37711076SCathy.Zhou@Sun.COM i_dladm_vnic_vrrp_mac(vrid_t vrid, int af, uint8_t *mac, uint_t maclen)
37811076SCathy.Zhou@Sun.COM {
37911076SCathy.Zhou@Sun.COM 	if (maclen < ETHERADDRL || vrid < VRRP_VRID_MIN ||
38011076SCathy.Zhou@Sun.COM 	    vrid > VRRP_VRID_MAX || (af != AF_INET && af != AF_INET6)) {
38111076SCathy.Zhou@Sun.COM 		return (DLADM_STATUS_BADARG);
38211076SCathy.Zhou@Sun.COM 	}
38311076SCathy.Zhou@Sun.COM 
38411076SCathy.Zhou@Sun.COM 	mac[0] = mac[1] = mac[3] = 0x0;
38511076SCathy.Zhou@Sun.COM 	mac[2] = 0x5e;
38611076SCathy.Zhou@Sun.COM 	mac[4] = (af == AF_INET) ? 0x01 : 0x02;
38711076SCathy.Zhou@Sun.COM 	mac[5] = vrid;
38811076SCathy.Zhou@Sun.COM 	return (DLADM_STATUS_OK);
38911076SCathy.Zhou@Sun.COM }
39011076SCathy.Zhou@Sun.COM 
39111076SCathy.Zhou@Sun.COM /*
3928275SEric Cheng  * Create a new VNIC / VLAN. Update the configuration file and bring it up.
39311076SCathy.Zhou@Sun.COM  * The "vrid" and "af" arguments are only required if the mac_addr_type is
39411076SCathy.Zhou@Sun.COM  * VNIC_MAC_ADDR_TYPE_VRID. In that case, the MAC address will be caculated
39511076SCathy.Zhou@Sun.COM  * based on the above algorithm.
3965084Sjohnlev  */
3975084Sjohnlev dladm_status_t
3988453SAnurag.Maskey@Sun.COM dladm_vnic_create(dladm_handle_t handle, const char *vnic, datalink_id_t linkid,
39911076SCathy.Zhou@Sun.COM     vnic_mac_addr_type_t mac_addr_type, uchar_t *mac_addr, uint_t mac_len,
40011076SCathy.Zhou@Sun.COM     int *mac_slot, uint_t mac_prefix_len, uint16_t vid, vrid_t vrid,
40111076SCathy.Zhou@Sun.COM     int af, datalink_id_t *vnic_id_out, dladm_arg_list_t *proplist,
40211076SCathy.Zhou@Sun.COM     uint32_t flags)
4035084Sjohnlev {
4048275SEric Cheng 	dladm_vnic_attr_t attr;
4055895Syz147064 	datalink_id_t vnic_id;
4065895Syz147064 	datalink_class_t class;
4078275SEric Cheng 	uint32_t media = DL_ETHER;
4088275SEric Cheng 	char name[MAXLINKNAMELEN];
4098275SEric Cheng 	uchar_t tmp_addr[MAXMACADDRLEN];
4105084Sjohnlev 	dladm_status_t status;
4118275SEric Cheng 	boolean_t is_vlan;
4128275SEric Cheng 	boolean_t is_etherstub;
4138275SEric Cheng 	int i;
41410491SRishi.Srivatsavai@Sun.COM 	boolean_t vnic_created = B_FALSE;
41510491SRishi.Srivatsavai@Sun.COM 	boolean_t conf_set = B_FALSE;
4165084Sjohnlev 
4175084Sjohnlev 	/*
4185084Sjohnlev 	 * Sanity test arguments.
4195084Sjohnlev 	 */
4208275SEric Cheng 	if ((flags & DLADM_OPT_ACTIVE) == 0)
4218275SEric Cheng 		return (DLADM_STATUS_NOTSUP);
4228275SEric Cheng 
4238275SEric Cheng 	is_vlan = ((flags & DLADM_OPT_VLAN) != 0);
4248275SEric Cheng 	if (is_vlan && ((vid < 1 || vid > 4094)))
4258275SEric Cheng 		return (DLADM_STATUS_VIDINVAL);
4268275SEric Cheng 
4278275SEric Cheng 	is_etherstub = (linkid == DATALINK_INVALID_LINKID);
4285084Sjohnlev 
4298275SEric Cheng 	if (!dladm_vnic_macaddrtype2str(mac_addr_type))
4305084Sjohnlev 		return (DLADM_STATUS_INVALIDMACADDRTYPE);
4315084Sjohnlev 
43211076SCathy.Zhou@Sun.COM 	if ((flags & DLADM_OPT_ANCHOR) == 0) {
43311076SCathy.Zhou@Sun.COM 		if ((status = dladm_datalink_id2info(handle, linkid, NULL,
43411076SCathy.Zhou@Sun.COM 		    &class, &media, NULL, 0)) != DLADM_STATUS_OK)
43511076SCathy.Zhou@Sun.COM 			return (status);
43611076SCathy.Zhou@Sun.COM 
43711076SCathy.Zhou@Sun.COM 		if (class == DATALINK_CLASS_VNIC ||
43811076SCathy.Zhou@Sun.COM 		    class == DATALINK_CLASS_VLAN)
43911076SCathy.Zhou@Sun.COM 			return (DLADM_STATUS_BADARG);
44011076SCathy.Zhou@Sun.COM 	} else {
44111076SCathy.Zhou@Sun.COM 		/* it's an anchor VNIC */
44211076SCathy.Zhou@Sun.COM 		if (linkid != DATALINK_INVALID_LINKID || vid != 0)
44311076SCathy.Zhou@Sun.COM 			return (DLADM_STATUS_BADARG);
44411076SCathy.Zhou@Sun.COM 	}
44511076SCathy.Zhou@Sun.COM 
44611076SCathy.Zhou@Sun.COM 	/*
44711076SCathy.Zhou@Sun.COM 	 * Only VRRP VNIC need VRID and address family specified.
44811076SCathy.Zhou@Sun.COM 	 */
44911076SCathy.Zhou@Sun.COM 	if (mac_addr_type != VNIC_MAC_ADDR_TYPE_VRID &&
45011076SCathy.Zhou@Sun.COM 	    (af != AF_UNSPEC || vrid != VRRP_VRID_NONE)) {
45111076SCathy.Zhou@Sun.COM 		return (DLADM_STATUS_BADARG);
45211076SCathy.Zhou@Sun.COM 	}
45311076SCathy.Zhou@Sun.COM 
4548275SEric Cheng 	/*
4558275SEric Cheng 	 * If a random address might be generated, but no prefix
4568275SEric Cheng 	 * was specified by the caller, use the default MAC address
4578275SEric Cheng 	 * prefix.
4588275SEric Cheng 	 */
4598275SEric Cheng 	if ((mac_addr_type == VNIC_MAC_ADDR_TYPE_RANDOM ||
4608275SEric Cheng 	    mac_addr_type == VNIC_MAC_ADDR_TYPE_AUTO) &&
4618275SEric Cheng 	    mac_prefix_len == 0) {
4628275SEric Cheng 		mac_prefix_len = sizeof (dladm_vnic_def_prefix);
4638275SEric Cheng 		mac_addr = tmp_addr;
4648275SEric Cheng 		bcopy(dladm_vnic_def_prefix, mac_addr, mac_prefix_len);
4655895Syz147064 	}
4665895Syz147064 
46711076SCathy.Zhou@Sun.COM 	/*
46811076SCathy.Zhou@Sun.COM 	 * If this is a VRRP VNIC, generate its MAC address using the given
46911076SCathy.Zhou@Sun.COM 	 * VRID and address family.
47011076SCathy.Zhou@Sun.COM 	 */
47111076SCathy.Zhou@Sun.COM 	if (mac_addr_type == VNIC_MAC_ADDR_TYPE_VRID) {
47211076SCathy.Zhou@Sun.COM 		/*
47311076SCathy.Zhou@Sun.COM 		 * VRRP VNICs must be created over ethernet data-links.
47411076SCathy.Zhou@Sun.COM 		 */
47511076SCathy.Zhou@Sun.COM 		if (vrid < VRRP_VRID_MIN || vrid > VRRP_VRID_MAX ||
47611076SCathy.Zhou@Sun.COM 		    (af != AF_INET && af != AF_INET6) || mac_addr != NULL ||
47711076SCathy.Zhou@Sun.COM 		    mac_len != 0 || mac_prefix_len != 0 ||
47811076SCathy.Zhou@Sun.COM 		    (mac_slot != NULL && *mac_slot != -1) || is_etherstub ||
47911076SCathy.Zhou@Sun.COM 		    media != DL_ETHER) {
48011076SCathy.Zhou@Sun.COM 			return (DLADM_STATUS_BADARG);
48111076SCathy.Zhou@Sun.COM 		}
48211076SCathy.Zhou@Sun.COM 		mac_len = ETHERADDRL;
48311076SCathy.Zhou@Sun.COM 		mac_addr = tmp_addr;
48411076SCathy.Zhou@Sun.COM 		status = i_dladm_vnic_vrrp_mac(vrid, af, mac_addr, mac_len);
48511076SCathy.Zhou@Sun.COM 		if (status != DLADM_STATUS_OK)
4868275SEric Cheng 			return (status);
48711076SCathy.Zhou@Sun.COM 	}
4888275SEric Cheng 
48911076SCathy.Zhou@Sun.COM 	if (mac_len > MAXMACADDRLEN)
49011076SCathy.Zhou@Sun.COM 		return (DLADM_STATUS_INVALIDMACADDRLEN);
4915084Sjohnlev 
4925895Syz147064 	if (vnic == NULL) {
4935895Syz147064 		flags |= DLADM_OPT_PREFIX;
4948275SEric Cheng 		(void) strlcpy(name, "vnic", sizeof (name));
4958275SEric Cheng 	} else {
4968275SEric Cheng 		(void) strlcpy(name, vnic, sizeof (name));
4975895Syz147064 	}
4985895Syz147064 
4998275SEric Cheng 	class = is_vlan ? DATALINK_CLASS_VLAN :
5008275SEric Cheng 	    (is_etherstub ? DATALINK_CLASS_ETHERSTUB : DATALINK_CLASS_VNIC);
5018453SAnurag.Maskey@Sun.COM 	if ((status = dladm_create_datalink_id(handle, name, class,
5028275SEric Cheng 	    media, flags, &vnic_id)) != DLADM_STATUS_OK)
5035895Syz147064 		return (status);
5048275SEric Cheng 
5058275SEric Cheng 	if ((flags & DLADM_OPT_PREFIX) != 0) {
5068275SEric Cheng 		(void) snprintf(name + 4, sizeof (name), "%llu", vnic_id);
5078275SEric Cheng 		flags &= ~DLADM_OPT_PREFIX;
5085084Sjohnlev 	}
5095084Sjohnlev 
5105084Sjohnlev 	bzero(&attr, sizeof (attr));
5118275SEric Cheng 
5128275SEric Cheng 	/* Extract resource_ctl and cpu_list from proplist */
5138275SEric Cheng 	if (proplist != NULL) {
5148453SAnurag.Maskey@Sun.COM 		status = dladm_link_proplist_extract(handle, proplist,
515*11878SVenu.Iyer@Sun.COM 		    &attr.va_resource_props, 0);
5168275SEric Cheng 		if (status != DLADM_STATUS_OK)
5178275SEric Cheng 			goto done;
5188275SEric Cheng 	}
5195084Sjohnlev 
5208275SEric Cheng 	attr.va_vnic_id = vnic_id;
5218275SEric Cheng 	attr.va_link_id = linkid;
5228275SEric Cheng 	attr.va_mac_addr_type = mac_addr_type;
5238275SEric Cheng 	attr.va_mac_len = mac_len;
5248275SEric Cheng 	if (mac_slot != NULL)
5258275SEric Cheng 		attr.va_mac_slot = *mac_slot;
5268275SEric Cheng 	if (mac_len > 0)
5278275SEric Cheng 		bcopy(mac_addr, attr.va_mac_addr, mac_len);
5288275SEric Cheng 	else if (mac_prefix_len > 0)
5298275SEric Cheng 		bcopy(mac_addr, attr.va_mac_addr, mac_prefix_len);
5308275SEric Cheng 	attr.va_mac_prefix_len = mac_prefix_len;
5318275SEric Cheng 	attr.va_vid = vid;
53211076SCathy.Zhou@Sun.COM 	attr.va_vrid = vrid;
53311076SCathy.Zhou@Sun.COM 	attr.va_af = af;
5348275SEric Cheng 	attr.va_force = (flags & DLADM_OPT_FORCE) != 0;
5358275SEric Cheng 
5368453SAnurag.Maskey@Sun.COM 	status = i_dladm_vnic_create_sys(handle, &attr);
5378275SEric Cheng 	if (status != DLADM_STATUS_OK)
5388275SEric Cheng 		goto done;
53910491SRishi.Srivatsavai@Sun.COM 	vnic_created = B_TRUE;
5408275SEric Cheng 
5418275SEric Cheng 	/* Save vnic configuration and its properties */
5428275SEric Cheng 	if (!(flags & DLADM_OPT_PERSIST))
5438275SEric Cheng 		goto done;
5448275SEric Cheng 
5458453SAnurag.Maskey@Sun.COM 	status = dladm_vnic_persist_conf(handle, name, &attr, class);
54610491SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK)
5475895Syz147064 		goto done;
54810491SRishi.Srivatsavai@Sun.COM 	conf_set = B_TRUE;
5495895Syz147064 
5508275SEric Cheng 	if (proplist != NULL) {
5518275SEric Cheng 		for (i = 0; i < proplist->al_count; i++) {
5528275SEric Cheng 			dladm_arg_info_t	*aip = &proplist->al_info[i];
5538275SEric Cheng 
5548453SAnurag.Maskey@Sun.COM 			status = dladm_set_linkprop(handle, vnic_id,
5558453SAnurag.Maskey@Sun.COM 			    aip->ai_name, aip->ai_val, aip->ai_count,
5568453SAnurag.Maskey@Sun.COM 			    DLADM_OPT_PERSIST);
5578275SEric Cheng 			if (status != DLADM_STATUS_OK)
5588275SEric Cheng 				break;
5598275SEric Cheng 		}
5608275SEric Cheng 	}
5615084Sjohnlev 
5625895Syz147064 done:
5635895Syz147064 	if (status != DLADM_STATUS_OK) {
56410491SRishi.Srivatsavai@Sun.COM 		if (conf_set)
56510491SRishi.Srivatsavai@Sun.COM 			(void) dladm_remove_conf(handle, vnic_id);
56610491SRishi.Srivatsavai@Sun.COM 		if (vnic_created)
56710491SRishi.Srivatsavai@Sun.COM 			(void) i_dladm_vnic_delete_sys(handle, vnic_id);
5688453SAnurag.Maskey@Sun.COM 		(void) dladm_destroy_datalink_id(handle, vnic_id, flags);
5695895Syz147064 	} else {
5708275SEric Cheng 		if (vnic_id_out != NULL)
5718275SEric Cheng 			*vnic_id_out = vnic_id;
5728275SEric Cheng 		if (mac_slot != NULL)
5738275SEric Cheng 			*mac_slot = attr.va_mac_slot;
5745895Syz147064 	}
57510491SRishi.Srivatsavai@Sun.COM 
57610491SRishi.Srivatsavai@Sun.COM 	if (is_vlan) {
57710491SRishi.Srivatsavai@Sun.COM 		dladm_status_t stat2;
57810491SRishi.Srivatsavai@Sun.COM 
57910491SRishi.Srivatsavai@Sun.COM 		stat2 = dladm_bridge_refresh(handle, linkid);
58010491SRishi.Srivatsavai@Sun.COM 		if (status == DLADM_STATUS_OK && stat2 != DLADM_STATUS_OK)
58110491SRishi.Srivatsavai@Sun.COM 			status = stat2;
58210491SRishi.Srivatsavai@Sun.COM 	}
5835084Sjohnlev 	return (status);
5845084Sjohnlev }
5855084Sjohnlev 
5865084Sjohnlev /*
5878275SEric Cheng  * Delete a VNIC / VLAN.
5885084Sjohnlev  */
5895084Sjohnlev dladm_status_t
5908453SAnurag.Maskey@Sun.COM dladm_vnic_delete(dladm_handle_t handle, datalink_id_t linkid, uint32_t flags)
5915084Sjohnlev {
5928275SEric Cheng 	dladm_status_t status;
5938275SEric Cheng 	datalink_class_t class;
5948275SEric Cheng 
5958275SEric Cheng 	if (flags == 0)
5968275SEric Cheng 		return (DLADM_STATUS_BADARG);
5975084Sjohnlev 
5988453SAnurag.Maskey@Sun.COM 	if ((dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, NULL, 0)
5998453SAnurag.Maskey@Sun.COM 	    != DLADM_STATUS_OK))
6008275SEric Cheng 		return (DLADM_STATUS_BADARG);
6015084Sjohnlev 
6028275SEric Cheng 	if ((flags & DLADM_OPT_VLAN) != 0) {
6038275SEric Cheng 		if (class != DATALINK_CLASS_VLAN)
6048275SEric Cheng 			return (DLADM_STATUS_BADARG);
6058275SEric Cheng 	} else {
6068275SEric Cheng 		if (class != DATALINK_CLASS_VNIC &&
6078275SEric Cheng 		    class != DATALINK_CLASS_ETHERSTUB)
6088275SEric Cheng 			return (DLADM_STATUS_BADARG);
6095084Sjohnlev 	}
6105084Sjohnlev 
6118275SEric Cheng 	if ((flags & DLADM_OPT_ACTIVE) != 0) {
6128453SAnurag.Maskey@Sun.COM 		status = i_dladm_vnic_delete_sys(handle, linkid);
6138275SEric Cheng 		if (status == DLADM_STATUS_OK) {
6148453SAnurag.Maskey@Sun.COM 			(void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0,
6158275SEric Cheng 			    DLADM_OPT_ACTIVE);
6168453SAnurag.Maskey@Sun.COM 			(void) dladm_destroy_datalink_id(handle, linkid,
6178275SEric Cheng 			    DLADM_OPT_ACTIVE);
6188275SEric Cheng 		} else if (status != DLADM_STATUS_NOTFOUND ||
6198275SEric Cheng 		    !(flags & DLADM_OPT_PERSIST)) {
6208275SEric Cheng 			return (status);
6218275SEric Cheng 		}
6228275SEric Cheng 	}
6238275SEric Cheng 	if ((flags & DLADM_OPT_PERSIST) != 0) {
62410616SSebastien.Roy@Sun.COM 		(void) dladm_remove_conf(handle, linkid);
6258453SAnurag.Maskey@Sun.COM 		(void) dladm_destroy_datalink_id(handle, linkid,
6268453SAnurag.Maskey@Sun.COM 		    DLADM_OPT_PERSIST);
6278275SEric Cheng 	}
62810491SRishi.Srivatsavai@Sun.COM 	return (dladm_bridge_refresh(handle, linkid));
6298275SEric Cheng }
6308275SEric Cheng 
6318275SEric Cheng static const char *
6328275SEric Cheng dladm_vnic_macaddr2str(const uchar_t *mac, char *buf)
6338275SEric Cheng {
6348275SEric Cheng 	static char unknown_mac[] = {0, 0, 0, 0, 0, 0};
6358275SEric Cheng 
6368275SEric Cheng 	if (buf == NULL)
6378275SEric Cheng 		return (NULL);
6388275SEric Cheng 
6398275SEric Cheng 	if (bcmp(unknown_mac, mac, ETHERADDRL) == 0)
6408275SEric Cheng 		(void) strlcpy(buf, "unknown", DLADM_STRSIZE);
6418275SEric Cheng 	else
6428275SEric Cheng 		return (_link_ntoa(mac, buf, ETHERADDRL, IFT_OTHER));
6438275SEric Cheng 
6448275SEric Cheng 	return (buf);
6458275SEric Cheng }
6468275SEric Cheng 
6478275SEric Cheng static dladm_status_t
6488275SEric Cheng dladm_vnic_str2macaddr(const char *str, uchar_t *buf)
6498275SEric Cheng {
6508275SEric Cheng 	int len = 0;
6518275SEric Cheng 	uchar_t *b = _link_aton(str, &len);
6528275SEric Cheng 
6538275SEric Cheng 	if (b == NULL || len >= MAXMACADDRLEN)
6548275SEric Cheng 		return (DLADM_STATUS_BADARG);
6558275SEric Cheng 
6568275SEric Cheng 	bcopy(b, buf, len);
6578275SEric Cheng 	free(b);
6588275SEric Cheng 	return (DLADM_STATUS_OK);
6595084Sjohnlev }
6605084Sjohnlev 
6615084Sjohnlev 
6628275SEric Cheng static dladm_status_t
6638453SAnurag.Maskey@Sun.COM dladm_vnic_persist_conf(dladm_handle_t handle, const char *name,
6648453SAnurag.Maskey@Sun.COM     dladm_vnic_attr_t *attrp, datalink_class_t class)
6658275SEric Cheng {
6668275SEric Cheng 	dladm_conf_t conf = DLADM_INVALID_CONF;
6678275SEric Cheng 	dladm_status_t status;
6688275SEric Cheng 	char macstr[ETHERADDRL * 3];
66910616SSebastien.Roy@Sun.COM 	char linkover[MAXLINKNAMELEN];
6708275SEric Cheng 	uint64_t u64;
6715084Sjohnlev 
6728453SAnurag.Maskey@Sun.COM 	if ((status = dladm_create_conf(handle, name, attrp->va_vnic_id,
6738275SEric Cheng 	    class, DL_ETHER, &conf)) != DLADM_STATUS_OK)
6745895Syz147064 		return (status);
6755895Syz147064 
6768275SEric Cheng 	if (attrp->va_link_id != DATALINK_INVALID_LINKID) {
67710616SSebastien.Roy@Sun.COM 		status = dladm_datalink_id2info(handle, attrp->va_link_id, NULL,
67810616SSebastien.Roy@Sun.COM 		    NULL, NULL, linkover, sizeof (linkover));
67910616SSebastien.Roy@Sun.COM 		if (status != DLADM_STATUS_OK)
68010616SSebastien.Roy@Sun.COM 			goto done;
6818453SAnurag.Maskey@Sun.COM 		status = dladm_set_conf_field(handle, conf, FLINKOVER,
68210616SSebastien.Roy@Sun.COM 		    DLADM_TYPE_STR, linkover);
6838275SEric Cheng 		if (status != DLADM_STATUS_OK)
6848275SEric Cheng 			goto done;
6858275SEric Cheng 	}
6868275SEric Cheng 
6878275SEric Cheng 	if (class != DATALINK_CLASS_VLAN) {
6888275SEric Cheng 		u64 = attrp->va_mac_addr_type;
6898453SAnurag.Maskey@Sun.COM 		status = dladm_set_conf_field(handle, conf, FMADDRTYPE,
6908275SEric Cheng 		    DLADM_TYPE_UINT64, &u64);
6918275SEric Cheng 		if (status != DLADM_STATUS_OK)
6928275SEric Cheng 			goto done;
6938275SEric Cheng 
69411076SCathy.Zhou@Sun.COM 		u64 = attrp->va_vrid;
69511076SCathy.Zhou@Sun.COM 		status = dladm_set_conf_field(handle, conf, FVRID,
69611076SCathy.Zhou@Sun.COM 		    DLADM_TYPE_UINT64, &u64);
69711076SCathy.Zhou@Sun.COM 		if (status != DLADM_STATUS_OK)
69811076SCathy.Zhou@Sun.COM 			goto done;
69911076SCathy.Zhou@Sun.COM 
70011076SCathy.Zhou@Sun.COM 		u64 = attrp->va_af;
70111076SCathy.Zhou@Sun.COM 		status = dladm_set_conf_field(handle, conf, FVRAF,
70211076SCathy.Zhou@Sun.COM 		    DLADM_TYPE_UINT64, &u64);
70311076SCathy.Zhou@Sun.COM 		if (status != DLADM_STATUS_OK)
70411076SCathy.Zhou@Sun.COM 			goto done;
70511076SCathy.Zhou@Sun.COM 
7068275SEric Cheng 		if (attrp->va_mac_len != ETHERADDRL) {
7078275SEric Cheng 			u64 = attrp->va_mac_len;
7088453SAnurag.Maskey@Sun.COM 			status = dladm_set_conf_field(handle, conf, FMADDRLEN,
7098275SEric Cheng 			    DLADM_TYPE_UINT64, &u64);
7108275SEric Cheng 			if (status != DLADM_STATUS_OK)
7118275SEric Cheng 				goto done;
7128275SEric Cheng 		}
7138275SEric Cheng 
7148275SEric Cheng 		if (attrp->va_mac_slot != -1) {
7158275SEric Cheng 			u64 = attrp->va_mac_slot;
71611076SCathy.Zhou@Sun.COM 			status = dladm_set_conf_field(handle, conf,
71711076SCathy.Zhou@Sun.COM 			    FMADDRSLOT, DLADM_TYPE_UINT64, &u64);
7188275SEric Cheng 			if (status != DLADM_STATUS_OK)
7198275SEric Cheng 			goto done;
7208275SEric Cheng 		}
7218275SEric Cheng 
7228275SEric Cheng 		if (attrp->va_mac_prefix_len !=
7238275SEric Cheng 		    sizeof (dladm_vnic_def_prefix)) {
7248275SEric Cheng 			u64 = attrp->va_mac_prefix_len;
7258453SAnurag.Maskey@Sun.COM 			status = dladm_set_conf_field(handle, conf,
7268453SAnurag.Maskey@Sun.COM 			    FMADDRPREFIXLEN, DLADM_TYPE_UINT64, &u64);
7278275SEric Cheng 			if (status != DLADM_STATUS_OK)
7288275SEric Cheng 				goto done;
7298275SEric Cheng 		}
7308275SEric Cheng 
7318275SEric Cheng 		(void) dladm_vnic_macaddr2str(attrp->va_mac_addr, macstr);
7328453SAnurag.Maskey@Sun.COM 		status = dladm_set_conf_field(handle, conf, FMACADDR,
7338453SAnurag.Maskey@Sun.COM 		    DLADM_TYPE_STR, macstr);
7348275SEric Cheng 		if (status != DLADM_STATUS_OK)
7358275SEric Cheng 			goto done;
7368275SEric Cheng 	}
7378275SEric Cheng 
7388275SEric Cheng 	if (attrp->va_vid != 0) {
7398275SEric Cheng 		u64 = attrp->va_vid;
7408453SAnurag.Maskey@Sun.COM 		status = dladm_set_conf_field(handle, conf, FVLANID,
7418275SEric Cheng 		    DLADM_TYPE_UINT64, &u64);
7428275SEric Cheng 		if (status != DLADM_STATUS_OK)
7438275SEric Cheng 			goto done;
7448275SEric Cheng 	}
7458275SEric Cheng 
7468275SEric Cheng 	/*
7478275SEric Cheng 	 * Commit the link configuration.
7488275SEric Cheng 	 */
7498453SAnurag.Maskey@Sun.COM 	status = dladm_write_conf(handle, conf);
7508275SEric Cheng 
7518275SEric Cheng done:
7528453SAnurag.Maskey@Sun.COM 	dladm_destroy_conf(handle, conf);
7535895Syz147064 	return (status);
7545084Sjohnlev }
7558275SEric Cheng 
7568275SEric Cheng typedef struct dladm_vnic_up_arg_s {
7578275SEric Cheng 	uint32_t	flags;
7588275SEric Cheng 	dladm_status_t	status;
7598275SEric Cheng } dladm_vnic_up_arg_t;
7608275SEric Cheng 
7618275SEric Cheng static int
7628453SAnurag.Maskey@Sun.COM i_dladm_vnic_up(dladm_handle_t handle, datalink_id_t linkid, void *arg)
7638275SEric Cheng {
7648275SEric Cheng 	dladm_status_t *statusp = &(((dladm_vnic_up_arg_t *)arg)->status);
7658275SEric Cheng 	dladm_vnic_attr_t attr;
7668275SEric Cheng 	dladm_status_t status;
7678275SEric Cheng 	dladm_arg_list_t *proplist;
7688275SEric Cheng 
7698275SEric Cheng 	bzero(&attr, sizeof (attr));
7708275SEric Cheng 
7718453SAnurag.Maskey@Sun.COM 	status = dladm_vnic_info(handle, linkid, &attr, DLADM_OPT_PERSIST);
7728275SEric Cheng 	if (status != DLADM_STATUS_OK)
7738275SEric Cheng 		goto done;
7748275SEric Cheng 
7758275SEric Cheng 	/* Get all properties for this vnic */
7768453SAnurag.Maskey@Sun.COM 	status = dladm_link_get_proplist(handle, linkid, &proplist);
7778275SEric Cheng 	if (status != DLADM_STATUS_OK)
7788275SEric Cheng 		goto done;
7798275SEric Cheng 
7808275SEric Cheng 	if (proplist != NULL) {
7818453SAnurag.Maskey@Sun.COM 		status = dladm_link_proplist_extract(handle, proplist,
782*11878SVenu.Iyer@Sun.COM 		    &attr.va_resource_props, DLADM_OPT_BOOT);
7838275SEric Cheng 	}
7848275SEric Cheng 
7858453SAnurag.Maskey@Sun.COM 	status = i_dladm_vnic_create_sys(handle, &attr);
78610491SRishi.Srivatsavai@Sun.COM 	if (status == DLADM_STATUS_OK) {
78710491SRishi.Srivatsavai@Sun.COM 		status = dladm_up_datalink_id(handle, linkid);
78810491SRishi.Srivatsavai@Sun.COM 		if (status != DLADM_STATUS_OK)
78910491SRishi.Srivatsavai@Sun.COM 			(void) i_dladm_vnic_delete_sys(handle, linkid);
79010491SRishi.Srivatsavai@Sun.COM 	}
7918275SEric Cheng 
7928275SEric Cheng done:
7938275SEric Cheng 	*statusp = status;
7948275SEric Cheng 	return (DLADM_WALK_CONTINUE);
7958275SEric Cheng }
7968275SEric Cheng 
7978275SEric Cheng dladm_status_t
7988453SAnurag.Maskey@Sun.COM dladm_vnic_up(dladm_handle_t handle, datalink_id_t linkid, uint32_t flags)
7998275SEric Cheng {
8008275SEric Cheng 	dladm_vnic_up_arg_t vnic_arg;
8018275SEric Cheng 	datalink_class_t class;
8028275SEric Cheng 
8038275SEric Cheng 	class = ((flags & DLADM_OPT_VLAN) != 0) ? DATALINK_CLASS_VLAN :
8048275SEric Cheng 	    (DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB);
8058275SEric Cheng 
8068275SEric Cheng 	if (linkid == DATALINK_ALL_LINKID) {
8078453SAnurag.Maskey@Sun.COM 		(void) dladm_walk_datalink_id(i_dladm_vnic_up, handle,
8088453SAnurag.Maskey@Sun.COM 		    &vnic_arg, class, DATALINK_ANY_MEDIATYPE,
8098453SAnurag.Maskey@Sun.COM 		    DLADM_OPT_PERSIST);
8108275SEric Cheng 		return (DLADM_STATUS_OK);
8118275SEric Cheng 	} else {
8128453SAnurag.Maskey@Sun.COM 		(void) i_dladm_vnic_up(handle, linkid, &vnic_arg);
8138275SEric Cheng 		return (vnic_arg.status);
8148275SEric Cheng 	}
8158275SEric Cheng }
816