xref: /titanic_44/usr/src/lib/libdladm/common/libdlvnic.c (revision 1cb875ae88fb9463b368e725c2444776595895cb)
1843e1988Sjohnlev /*
2843e1988Sjohnlev  * CDDL HEADER START
3843e1988Sjohnlev  *
4843e1988Sjohnlev  * The contents of this file are subject to the terms of the
5843e1988Sjohnlev  * Common Development and Distribution License (the "License").
6843e1988Sjohnlev  * You may not use this file except in compliance with the License.
7843e1988Sjohnlev  *
8843e1988Sjohnlev  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9843e1988Sjohnlev  * or http://www.opensolaris.org/os/licensing.
10843e1988Sjohnlev  * See the License for the specific language governing permissions
11843e1988Sjohnlev  * and limitations under the License.
12843e1988Sjohnlev  *
13843e1988Sjohnlev  * When distributing Covered Code, include this CDDL HEADER in each
14843e1988Sjohnlev  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15843e1988Sjohnlev  * If applicable, add the following below this CDDL HEADER, with the
16843e1988Sjohnlev  * fields enclosed by brackets "[]" replaced with your own identifying
17843e1988Sjohnlev  * information: Portions Copyright [yyyy] [name of copyright owner]
18843e1988Sjohnlev  *
19843e1988Sjohnlev  * CDDL HEADER END
20843e1988Sjohnlev  */
21843e1988Sjohnlev /*
224eaa4710SRishi Srivatsavai  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23843e1988Sjohnlev  * Use is subject to license terms.
24843e1988Sjohnlev  */
25843e1988Sjohnlev 
26843e1988Sjohnlev #include <stdio.h>
27843e1988Sjohnlev #include <sys/types.h>
28843e1988Sjohnlev #include <sys/stat.h>
29843e1988Sjohnlev #include <string.h>
30843e1988Sjohnlev #include <fcntl.h>
31843e1988Sjohnlev #include <unistd.h>
32843e1988Sjohnlev #include <stropts.h>
33843e1988Sjohnlev #include <stdlib.h>
34843e1988Sjohnlev #include <errno.h>
35843e1988Sjohnlev #include <strings.h>
36843e1988Sjohnlev #include <libintl.h>
37843e1988Sjohnlev #include <net/if_types.h>
38843e1988Sjohnlev #include <net/if_dl.h>
39da14cebeSEric Cheng #include <sys/dld.h>
40843e1988Sjohnlev #include <libdladm_impl.h>
41*1cb875aeSCathy Zhou #include <libvrrpadm.h>
42d62bc4baSyz147064 #include <libdllink.h>
434eaa4710SRishi Srivatsavai #include <libdlbridge.h>
44843e1988Sjohnlev #include <libdlvnic.h>
45843e1988Sjohnlev 
46843e1988Sjohnlev /*
47843e1988Sjohnlev  * VNIC administration library.
48843e1988Sjohnlev  */
49843e1988Sjohnlev 
50da14cebeSEric Cheng /*
51da14cebeSEric Cheng  * Default random MAC address prefix (locally administered).
52da14cebeSEric Cheng  */
53da14cebeSEric Cheng static char dladm_vnic_def_prefix[] = {0x02, 0x08, 0x20};
54843e1988Sjohnlev 
554ac67f02SAnurag S. Maskey static dladm_status_t	dladm_vnic_persist_conf(dladm_handle_t,
564ac67f02SAnurag S. Maskey 			    const char *name, dladm_vnic_attr_t *,
574ac67f02SAnurag S. Maskey 			    datalink_class_t);
58da14cebeSEric Cheng static const char	*dladm_vnic_macaddr2str(const uchar_t *, char *);
59da14cebeSEric Cheng static dladm_status_t	dladm_vnic_str2macaddr(const char *, uchar_t *);
60843e1988Sjohnlev 
61843e1988Sjohnlev /*
62da14cebeSEric Cheng  * Convert a diagnostic returned by the kernel into a dladm_status_t.
63843e1988Sjohnlev  */
64843e1988Sjohnlev static dladm_status_t
65da14cebeSEric Cheng dladm_vnic_diag2status(vnic_ioc_diag_t ioc_diag)
66843e1988Sjohnlev {
67da14cebeSEric Cheng 	switch (ioc_diag) {
68*1cb875aeSCathy Zhou 	case VNIC_IOC_DIAG_NONE:
69*1cb875aeSCathy Zhou 		return (DLADM_STATUS_OK);
70da14cebeSEric Cheng 	case VNIC_IOC_DIAG_MACADDRLEN_INVALID:
71da14cebeSEric Cheng 		return (DLADM_STATUS_INVALIDMACADDRLEN);
72da14cebeSEric Cheng 	case VNIC_IOC_DIAG_MACADDR_NIC:
73da14cebeSEric Cheng 		return (DLADM_STATUS_INVALIDMACADDRNIC);
74da14cebeSEric Cheng 	case VNIC_IOC_DIAG_MACADDR_INUSE:
75da14cebeSEric Cheng 		return (DLADM_STATUS_INVALIDMACADDRINUSE);
76da14cebeSEric Cheng 	case VNIC_IOC_DIAG_MACFACTORYSLOTINVALID:
77da14cebeSEric Cheng 		return (DLADM_STATUS_MACFACTORYSLOTINVALID);
78da14cebeSEric Cheng 	case VNIC_IOC_DIAG_MACFACTORYSLOTUSED:
79da14cebeSEric Cheng 		return (DLADM_STATUS_MACFACTORYSLOTUSED);
80da14cebeSEric Cheng 	case VNIC_IOC_DIAG_MACFACTORYSLOTALLUSED:
81da14cebeSEric Cheng 		return (DLADM_STATUS_MACFACTORYSLOTALLUSED);
82da14cebeSEric Cheng 	case VNIC_IOC_DIAG_MACFACTORYNOTSUP:
83da14cebeSEric Cheng 		return (DLADM_STATUS_MACFACTORYNOTSUP);
84da14cebeSEric Cheng 	case VNIC_IOC_DIAG_MACPREFIX_INVALID:
85da14cebeSEric Cheng 		return (DLADM_STATUS_INVALIDMACPREFIX);
86da14cebeSEric Cheng 	case VNIC_IOC_DIAG_MACPREFIXLEN_INVALID:
87da14cebeSEric Cheng 		return (DLADM_STATUS_INVALIDMACPREFIXLEN);
88da14cebeSEric Cheng 	case VNIC_IOC_DIAG_MACMARGIN_INVALID:
89da14cebeSEric Cheng 		return (DLADM_STATUS_INVALID_MACMARGIN);
90da14cebeSEric Cheng 	case VNIC_IOC_DIAG_NO_HWRINGS:
91da14cebeSEric Cheng 		return (DLADM_STATUS_NO_HWRINGS);
92*1cb875aeSCathy Zhou 	case VNIC_IOC_DIAG_MACADDR_INVALID:
93*1cb875aeSCathy Zhou 		return (DLADM_STATUS_INVALIDMACADDR);
94*1cb875aeSCathy Zhou 	default:
95*1cb875aeSCathy Zhou 		return (DLADM_STATUS_FAILED);
96da14cebeSEric Cheng 	}
97843e1988Sjohnlev }
98843e1988Sjohnlev 
99843e1988Sjohnlev /*
100da14cebeSEric Cheng  * Send a create command to the VNIC driver.
101843e1988Sjohnlev  */
102da14cebeSEric Cheng dladm_status_t
1034ac67f02SAnurag S. Maskey i_dladm_vnic_create_sys(dladm_handle_t handle, dladm_vnic_attr_t *attr)
104843e1988Sjohnlev {
1054ac67f02SAnurag S. Maskey 	int rc;
106da14cebeSEric Cheng 	vnic_ioc_create_t ioc;
107eae72b5bSSebastien Roy 	dladm_status_t status = DLADM_STATUS_OK;
108843e1988Sjohnlev 
109da14cebeSEric Cheng 	bzero(&ioc, sizeof (ioc));
110da14cebeSEric Cheng 	ioc.vc_vnic_id = attr->va_vnic_id;
111da14cebeSEric Cheng 	ioc.vc_link_id = attr->va_link_id;
112da14cebeSEric Cheng 	ioc.vc_mac_addr_type = attr->va_mac_addr_type;
113da14cebeSEric Cheng 	ioc.vc_mac_len = attr->va_mac_len;
114da14cebeSEric Cheng 	ioc.vc_mac_slot = attr->va_mac_slot;
115da14cebeSEric Cheng 	ioc.vc_mac_prefix_len = attr->va_mac_prefix_len;
116da14cebeSEric Cheng 	ioc.vc_vid = attr->va_vid;
117*1cb875aeSCathy Zhou 	ioc.vc_vrid = attr->va_vrid;
118*1cb875aeSCathy Zhou 	ioc.vc_af = attr->va_af;
119da14cebeSEric Cheng 	ioc.vc_flags = attr->va_force ? VNIC_IOC_CREATE_FORCE : 0;
120da14cebeSEric Cheng 	ioc.vc_flags |= attr->va_hwrings ? VNIC_IOC_CREATE_REQ_HWRINGS : 0;
121843e1988Sjohnlev 
122da14cebeSEric Cheng 	if (attr->va_mac_len > 0 || ioc.vc_mac_prefix_len > 0)
123da14cebeSEric Cheng 		bcopy(attr->va_mac_addr, ioc.vc_mac_addr, MAXMACADDRLEN);
124da14cebeSEric Cheng 	bcopy(&attr->va_resource_props, &ioc.vc_resource_props,
125da14cebeSEric Cheng 	    sizeof (mac_resource_props_t));
126da14cebeSEric Cheng 	if (attr->va_link_id == DATALINK_INVALID_LINKID)
127da14cebeSEric Cheng 		ioc.vc_flags |= VNIC_IOC_CREATE_ANCHOR;
128843e1988Sjohnlev 
1294ac67f02SAnurag S. Maskey 	rc = ioctl(dladm_dld_fd(handle), VNIC_IOC_CREATE, &ioc);
130da14cebeSEric Cheng 	if (rc < 0)
131eae72b5bSSebastien Roy 		status = dladm_errno2status(errno);
132843e1988Sjohnlev 
133da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK) {
134da14cebeSEric Cheng 		if (ioc.vc_diag != VNIC_IOC_DIAG_NONE)
135da14cebeSEric Cheng 			status = dladm_vnic_diag2status(ioc.vc_diag);
136da14cebeSEric Cheng 	}
137da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
138da14cebeSEric Cheng 		return (status);
139da14cebeSEric Cheng 
140da14cebeSEric Cheng 	attr->va_mac_addr_type = ioc.vc_mac_addr_type;
141da14cebeSEric Cheng 	switch (ioc.vc_mac_addr_type) {
142da14cebeSEric Cheng 	case VNIC_MAC_ADDR_TYPE_FACTORY:
143da14cebeSEric Cheng 		attr->va_mac_slot = ioc.vc_mac_slot;
144da14cebeSEric Cheng 		break;
145da14cebeSEric Cheng 	case VNIC_MAC_ADDR_TYPE_RANDOM:
146da14cebeSEric Cheng 		bcopy(ioc.vc_mac_addr, attr->va_mac_addr, MAXMACADDRLEN);
147da14cebeSEric Cheng 		attr->va_mac_len = ioc.vc_mac_len;
148da14cebeSEric Cheng 		break;
149da14cebeSEric Cheng 	}
150eae72b5bSSebastien Roy 	return (status);
151843e1988Sjohnlev }
152843e1988Sjohnlev 
153843e1988Sjohnlev /*
154d62bc4baSyz147064  * Get the configuration information of the given VNIC.
155843e1988Sjohnlev  */
156da14cebeSEric Cheng static dladm_status_t
1574ac67f02SAnurag S. Maskey i_dladm_vnic_info_active(dladm_handle_t handle, datalink_id_t linkid,
1584ac67f02SAnurag S. Maskey     dladm_vnic_attr_t *attrp)
159843e1988Sjohnlev {
160da14cebeSEric Cheng 	vnic_ioc_info_t ioc;
161da14cebeSEric Cheng 	vnic_info_t *vnic;
1624ac67f02SAnurag S. Maskey 	int rc;
163843e1988Sjohnlev 	dladm_status_t status = DLADM_STATUS_OK;
164843e1988Sjohnlev 
165da14cebeSEric Cheng 	bzero(&ioc, sizeof (ioc));
166da14cebeSEric Cheng 	vnic = &ioc.vi_info;
167da14cebeSEric Cheng 	vnic->vn_vnic_id = linkid;
168843e1988Sjohnlev 
1694ac67f02SAnurag S. Maskey 	rc = ioctl(dladm_dld_fd(handle), VNIC_IOC_INFO, &ioc);
170da14cebeSEric Cheng 	if (rc != 0) {
171843e1988Sjohnlev 		status = dladm_errno2status(errno);
172843e1988Sjohnlev 		goto bail;
173843e1988Sjohnlev 	}
174843e1988Sjohnlev 
175d62bc4baSyz147064 	attrp->va_vnic_id = vnic->vn_vnic_id;
176d62bc4baSyz147064 	attrp->va_link_id = vnic->vn_link_id;
177d62bc4baSyz147064 	attrp->va_mac_addr_type = vnic->vn_mac_addr_type;
178da14cebeSEric Cheng 	bcopy(vnic->vn_mac_addr, attrp->va_mac_addr, MAXMACADDRLEN);
179d62bc4baSyz147064 	attrp->va_mac_len = vnic->vn_mac_len;
180da14cebeSEric Cheng 	attrp->va_mac_slot = vnic->vn_mac_slot;
181da14cebeSEric Cheng 	attrp->va_mac_prefix_len = vnic->vn_mac_prefix_len;
182da14cebeSEric Cheng 	attrp->va_vid = vnic->vn_vid;
183*1cb875aeSCathy Zhou 	attrp->va_vrid = vnic->vn_vrid;
184*1cb875aeSCathy Zhou 	attrp->va_af = vnic->vn_af;
185da14cebeSEric Cheng 	attrp->va_force = vnic->vn_force;
186843e1988Sjohnlev 
187843e1988Sjohnlev bail:
188843e1988Sjohnlev 	return (status);
189843e1988Sjohnlev }
190843e1988Sjohnlev 
191da14cebeSEric Cheng static dladm_status_t
1924ac67f02SAnurag S. Maskey i_dladm_vnic_info_persist(dladm_handle_t handle, datalink_id_t linkid,
1934ac67f02SAnurag S. Maskey     dladm_vnic_attr_t *attrp)
194da14cebeSEric Cheng {
195da14cebeSEric Cheng 	dladm_conf_t conf;
196da14cebeSEric Cheng 	dladm_status_t status;
197da14cebeSEric Cheng 	char macstr[ETHERADDRL * 3];
1982b24ab6bSSebastien Roy 	char linkover[MAXLINKNAMELEN];
199da14cebeSEric Cheng 	uint64_t u64;
200da14cebeSEric Cheng 	datalink_class_t class;
201da14cebeSEric Cheng 
202da14cebeSEric Cheng 	attrp->va_vnic_id = linkid;
2034ac67f02SAnurag S. Maskey 	if ((status = dladm_read_conf(handle, linkid, &conf)) !=
2044ac67f02SAnurag S. Maskey 	    DLADM_STATUS_OK)
205da14cebeSEric Cheng 		return (status);
206da14cebeSEric Cheng 
2072b24ab6bSSebastien Roy 	status = dladm_get_conf_field(handle, conf, FLINKOVER, linkover,
2082b24ab6bSSebastien Roy 	    sizeof (linkover));
2092b24ab6bSSebastien Roy 	if (status != DLADM_STATUS_OK) {
2102b24ab6bSSebastien Roy 		/*
2112b24ab6bSSebastien Roy 		 * This isn't an error, etherstubs don't have a FLINKOVER
2122b24ab6bSSebastien Roy 		 * property.
2132b24ab6bSSebastien Roy 		 */
2142b24ab6bSSebastien Roy 		attrp->va_link_id = DATALINK_INVALID_LINKID;
2152b24ab6bSSebastien Roy 	} else {
2162b24ab6bSSebastien Roy 		if ((status = dladm_name2info(handle, linkover,
2172b24ab6bSSebastien Roy 		    &attrp->va_link_id, NULL, NULL, NULL)) != DLADM_STATUS_OK)
2182b24ab6bSSebastien Roy 			goto done;
2192b24ab6bSSebastien Roy 	}
220da14cebeSEric Cheng 
2214ac67f02SAnurag S. Maskey 	status = dladm_get_conf_field(handle, conf, FHWRINGS,
2224ac67f02SAnurag S. Maskey 	    &attrp->va_hwrings, sizeof (boolean_t));
223da14cebeSEric Cheng 
224da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK && status != DLADM_STATUS_NOTFOUND)
225da14cebeSEric Cheng 		goto done;
226da14cebeSEric Cheng 	if (status == DLADM_STATUS_NOTFOUND)
227da14cebeSEric Cheng 		attrp->va_hwrings = B_FALSE;
228da14cebeSEric Cheng 
2294ac67f02SAnurag S. Maskey 	if ((status = dladm_datalink_id2info(handle, linkid, NULL, &class,
230da14cebeSEric Cheng 	    NULL, NULL, 0)) != DLADM_STATUS_OK)
231da14cebeSEric Cheng 		goto done;
232da14cebeSEric Cheng 
233da14cebeSEric Cheng 	if (class == DATALINK_CLASS_VLAN) {
234da14cebeSEric Cheng 		if (attrp->va_link_id == DATALINK_INVALID_LINKID) {
235da14cebeSEric Cheng 			status = DLADM_STATUS_BADARG;
236da14cebeSEric Cheng 			goto done;
237da14cebeSEric Cheng 		}
238da14cebeSEric Cheng 		attrp->va_mac_addr_type = VNIC_MAC_ADDR_TYPE_PRIMARY;
239da14cebeSEric Cheng 		attrp->va_mac_len = 0;
240da14cebeSEric Cheng 	} else {
2414ac67f02SAnurag S. Maskey 		status = dladm_get_conf_field(handle, conf, FMADDRTYPE, &u64,
242da14cebeSEric Cheng 		    sizeof (u64));
243da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK)
244da14cebeSEric Cheng 			goto done;
245da14cebeSEric Cheng 
246da14cebeSEric Cheng 		attrp->va_mac_addr_type = (vnic_mac_addr_type_t)u64;
247da14cebeSEric Cheng 
248*1cb875aeSCathy Zhou 		if ((status = dladm_get_conf_field(handle, conf, FVRID,
249*1cb875aeSCathy Zhou 		    &u64, sizeof (u64))) != DLADM_STATUS_OK) {
250*1cb875aeSCathy Zhou 			attrp->va_vrid = VRRP_VRID_NONE;
251*1cb875aeSCathy Zhou 		} else {
252*1cb875aeSCathy Zhou 			attrp->va_vrid = (vrid_t)u64;
253*1cb875aeSCathy Zhou 		}
254*1cb875aeSCathy Zhou 
255*1cb875aeSCathy Zhou 		if ((status = dladm_get_conf_field(handle, conf, FVRAF,
256*1cb875aeSCathy Zhou 		    &u64, sizeof (u64))) != DLADM_STATUS_OK) {
257*1cb875aeSCathy Zhou 			attrp->va_af = AF_UNSPEC;
258*1cb875aeSCathy Zhou 		} else {
259*1cb875aeSCathy Zhou 			attrp->va_af = (int)u64;
260*1cb875aeSCathy Zhou 		}
261*1cb875aeSCathy Zhou 
2624ac67f02SAnurag S. Maskey 		status = dladm_get_conf_field(handle, conf, FMADDRLEN, &u64,
263da14cebeSEric Cheng 		    sizeof (u64));
264da14cebeSEric Cheng 		attrp->va_mac_len = ((status == DLADM_STATUS_OK) ?
265da14cebeSEric Cheng 		    (uint_t)u64 : ETHERADDRL);
266da14cebeSEric Cheng 
2674ac67f02SAnurag S. Maskey 		status = dladm_get_conf_field(handle, conf, FMADDRSLOT, &u64,
268da14cebeSEric Cheng 		    sizeof (u64));
269da14cebeSEric Cheng 		attrp->va_mac_slot = ((status == DLADM_STATUS_OK) ?
270da14cebeSEric Cheng 		    (int)u64 : -1);
271da14cebeSEric Cheng 
2724ac67f02SAnurag S. Maskey 		status = dladm_get_conf_field(handle, conf, FMADDRPREFIXLEN,
2734ac67f02SAnurag S. Maskey 		    &u64, sizeof (u64));
274da14cebeSEric Cheng 		attrp->va_mac_prefix_len = ((status == DLADM_STATUS_OK) ?
275da14cebeSEric Cheng 		    (uint_t)u64 : sizeof (dladm_vnic_def_prefix));
276da14cebeSEric Cheng 
2774ac67f02SAnurag S. Maskey 		status = dladm_get_conf_field(handle, conf, FMACADDR, macstr,
278da14cebeSEric Cheng 		    sizeof (macstr));
279da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK)
280da14cebeSEric Cheng 			goto done;
281da14cebeSEric Cheng 
282da14cebeSEric Cheng 		status = dladm_vnic_str2macaddr(macstr, attrp->va_mac_addr);
283da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK)
284da14cebeSEric Cheng 			goto done;
285da14cebeSEric Cheng 	}
286da14cebeSEric Cheng 
2874ac67f02SAnurag S. Maskey 	status = dladm_get_conf_field(handle, conf, FVLANID, &u64,
2884ac67f02SAnurag S. Maskey 	    sizeof (u64));
289da14cebeSEric Cheng 	attrp->va_vid = ((status == DLADM_STATUS_OK) ?  (uint16_t)u64 : 0);
290da14cebeSEric Cheng 
291da14cebeSEric Cheng 
292da14cebeSEric Cheng 	status = DLADM_STATUS_OK;
293da14cebeSEric Cheng done:
2944ac67f02SAnurag S. Maskey 	dladm_destroy_conf(handle, conf);
295da14cebeSEric Cheng 	return (status);
296da14cebeSEric Cheng }
297da14cebeSEric Cheng 
298da14cebeSEric Cheng dladm_status_t
2994ac67f02SAnurag S. Maskey dladm_vnic_info(dladm_handle_t handle, datalink_id_t linkid,
3004ac67f02SAnurag S. Maskey     dladm_vnic_attr_t *attrp, uint32_t flags)
301da14cebeSEric Cheng {
302da14cebeSEric Cheng 	if (flags == DLADM_OPT_ACTIVE)
3034ac67f02SAnurag S. Maskey 		return (i_dladm_vnic_info_active(handle, linkid, attrp));
304da14cebeSEric Cheng 	else if (flags == DLADM_OPT_PERSIST)
3054ac67f02SAnurag S. Maskey 		return (i_dladm_vnic_info_persist(handle, linkid, attrp));
306da14cebeSEric Cheng 	else
307da14cebeSEric Cheng 		return (DLADM_STATUS_BADARG);
308da14cebeSEric Cheng }
309da14cebeSEric Cheng 
310843e1988Sjohnlev /*
311843e1988Sjohnlev  * Remove a VNIC from the kernel.
312843e1988Sjohnlev  */
313da14cebeSEric Cheng dladm_status_t
3144ac67f02SAnurag S. Maskey i_dladm_vnic_delete_sys(dladm_handle_t handle, datalink_id_t linkid)
315843e1988Sjohnlev {
316843e1988Sjohnlev 	vnic_ioc_delete_t ioc;
317da14cebeSEric Cheng 	dladm_status_t status = DLADM_STATUS_OK;
3184ac67f02SAnurag S. Maskey 	int rc;
319843e1988Sjohnlev 
320da14cebeSEric Cheng 	ioc.vd_vnic_id = linkid;
321da14cebeSEric Cheng 
3224ac67f02SAnurag S. Maskey 	rc = ioctl(dladm_dld_fd(handle), VNIC_IOC_DELETE, &ioc);
323da14cebeSEric Cheng 	if (rc < 0)
324da14cebeSEric Cheng 		status = dladm_errno2status(errno);
325da14cebeSEric Cheng 
326da14cebeSEric Cheng 	return (status);
327843e1988Sjohnlev }
328843e1988Sjohnlev 
329843e1988Sjohnlev /*
330843e1988Sjohnlev  * Convert between MAC address types and their string representations.
331843e1988Sjohnlev  */
332843e1988Sjohnlev 
333843e1988Sjohnlev typedef struct dladm_vnic_addr_type_s {
334da14cebeSEric Cheng 	const char		*va_str;
335843e1988Sjohnlev 	vnic_mac_addr_type_t	va_type;
336843e1988Sjohnlev } dladm_vnic_addr_type_t;
337843e1988Sjohnlev 
338843e1988Sjohnlev static dladm_vnic_addr_type_t addr_types[] = {
339843e1988Sjohnlev 	{"fixed", VNIC_MAC_ADDR_TYPE_FIXED},
340da14cebeSEric Cheng 	{"random", VNIC_MAC_ADDR_TYPE_RANDOM},
341da14cebeSEric Cheng 	{"factory", VNIC_MAC_ADDR_TYPE_FACTORY},
342da14cebeSEric Cheng 	{"auto", VNIC_MAC_ADDR_TYPE_AUTO},
343*1cb875aeSCathy Zhou 	{"fixed", VNIC_MAC_ADDR_TYPE_PRIMARY},
344*1cb875aeSCathy Zhou 	{"vrrp", VNIC_MAC_ADDR_TYPE_VRID}
345843e1988Sjohnlev };
346843e1988Sjohnlev 
347843e1988Sjohnlev #define	NADDR_TYPES (sizeof (addr_types) / sizeof (dladm_vnic_addr_type_t))
348843e1988Sjohnlev 
349da14cebeSEric Cheng static const char *
350da14cebeSEric Cheng dladm_vnic_macaddrtype2str(vnic_mac_addr_type_t type)
351da14cebeSEric Cheng {
352da14cebeSEric Cheng 	int i;
353da14cebeSEric Cheng 
354da14cebeSEric Cheng 	for (i = 0; i < NADDR_TYPES; i++) {
355da14cebeSEric Cheng 		if (type == addr_types[i].va_type)
356da14cebeSEric Cheng 			return (addr_types[i].va_str);
357da14cebeSEric Cheng 	}
358da14cebeSEric Cheng 	return (NULL);
359da14cebeSEric Cheng }
360da14cebeSEric Cheng 
361d62bc4baSyz147064 dladm_status_t
362d62bc4baSyz147064 dladm_vnic_str2macaddrtype(const char *str, vnic_mac_addr_type_t *val)
363843e1988Sjohnlev {
364843e1988Sjohnlev 	int i;
365843e1988Sjohnlev 	dladm_vnic_addr_type_t *type;
366843e1988Sjohnlev 
367843e1988Sjohnlev 	for (i = 0; i < NADDR_TYPES; i++) {
368843e1988Sjohnlev 		type = &addr_types[i];
369843e1988Sjohnlev 		if (strncmp(str, type->va_str, strlen(type->va_str)) == 0) {
370843e1988Sjohnlev 			*val = type->va_type;
371843e1988Sjohnlev 			return (DLADM_STATUS_OK);
372843e1988Sjohnlev 		}
373843e1988Sjohnlev 	}
374d62bc4baSyz147064 	return (DLADM_STATUS_BADARG);
375843e1988Sjohnlev }
376843e1988Sjohnlev 
377843e1988Sjohnlev /*
378*1cb875aeSCathy Zhou  * Based on the VRRP specification, the virtual router MAC address associated
379*1cb875aeSCathy Zhou  * with a virtual router is an IEEE 802 MAC address in the following format:
380*1cb875aeSCathy Zhou  *
381*1cb875aeSCathy Zhou  * IPv4 case: 00-00-5E-00-01-{VRID} (in hex in internet standard bit-order)
382*1cb875aeSCathy Zhou  *
383*1cb875aeSCathy Zhou  * IPv6 case: 00-00-5E-00-02-{VRID} (in hex in internet standard bit-order)
384*1cb875aeSCathy Zhou  */
385*1cb875aeSCathy Zhou static dladm_status_t
386*1cb875aeSCathy Zhou i_dladm_vnic_vrrp_mac(vrid_t vrid, int af, uint8_t *mac, uint_t maclen)
387*1cb875aeSCathy Zhou {
388*1cb875aeSCathy Zhou 	if (maclen < ETHERADDRL || vrid < VRRP_VRID_MIN ||
389*1cb875aeSCathy Zhou 	    vrid > VRRP_VRID_MAX || (af != AF_INET && af != AF_INET6)) {
390*1cb875aeSCathy Zhou 		return (DLADM_STATUS_BADARG);
391*1cb875aeSCathy Zhou 	}
392*1cb875aeSCathy Zhou 
393*1cb875aeSCathy Zhou 	mac[0] = mac[1] = mac[3] = 0x0;
394*1cb875aeSCathy Zhou 	mac[2] = 0x5e;
395*1cb875aeSCathy Zhou 	mac[4] = (af == AF_INET) ? 0x01 : 0x02;
396*1cb875aeSCathy Zhou 	mac[5] = vrid;
397*1cb875aeSCathy Zhou 	return (DLADM_STATUS_OK);
398*1cb875aeSCathy Zhou }
399*1cb875aeSCathy Zhou 
400*1cb875aeSCathy Zhou /*
401da14cebeSEric Cheng  * Create a new VNIC / VLAN. Update the configuration file and bring it up.
402*1cb875aeSCathy Zhou  * The "vrid" and "af" arguments are only required if the mac_addr_type is
403*1cb875aeSCathy Zhou  * VNIC_MAC_ADDR_TYPE_VRID. In that case, the MAC address will be caculated
404*1cb875aeSCathy Zhou  * based on the above algorithm.
405843e1988Sjohnlev  */
406843e1988Sjohnlev dladm_status_t
4074ac67f02SAnurag S. Maskey dladm_vnic_create(dladm_handle_t handle, const char *vnic, datalink_id_t linkid,
408*1cb875aeSCathy Zhou     vnic_mac_addr_type_t mac_addr_type, uchar_t *mac_addr, uint_t mac_len,
409*1cb875aeSCathy Zhou     int *mac_slot, uint_t mac_prefix_len, uint16_t vid, vrid_t vrid,
410*1cb875aeSCathy Zhou     int af, datalink_id_t *vnic_id_out, dladm_arg_list_t *proplist,
411*1cb875aeSCathy Zhou     uint32_t flags)
412843e1988Sjohnlev {
413da14cebeSEric Cheng 	dladm_vnic_attr_t attr;
414d62bc4baSyz147064 	datalink_id_t vnic_id;
415d62bc4baSyz147064 	datalink_class_t class;
416da14cebeSEric Cheng 	uint32_t media = DL_ETHER;
417da14cebeSEric Cheng 	char name[MAXLINKNAMELEN];
418da14cebeSEric Cheng 	uchar_t tmp_addr[MAXMACADDRLEN];
419843e1988Sjohnlev 	dladm_status_t status;
420da14cebeSEric Cheng 	boolean_t is_vlan;
421da14cebeSEric Cheng 	boolean_t is_etherstub;
422da14cebeSEric Cheng 	int i;
4234eaa4710SRishi Srivatsavai 	boolean_t vnic_created = B_FALSE;
4244eaa4710SRishi Srivatsavai 	boolean_t conf_set = B_FALSE;
425843e1988Sjohnlev 
426843e1988Sjohnlev 	/*
427843e1988Sjohnlev 	 * Sanity test arguments.
428843e1988Sjohnlev 	 */
429da14cebeSEric Cheng 	if ((flags & DLADM_OPT_ACTIVE) == 0)
430da14cebeSEric Cheng 		return (DLADM_STATUS_NOTSUP);
431da14cebeSEric Cheng 
432da14cebeSEric Cheng 	is_vlan = ((flags & DLADM_OPT_VLAN) != 0);
433da14cebeSEric Cheng 	if (is_vlan && ((vid < 1 || vid > 4094)))
434da14cebeSEric Cheng 		return (DLADM_STATUS_VIDINVAL);
435da14cebeSEric Cheng 
436da14cebeSEric Cheng 	is_etherstub = (linkid == DATALINK_INVALID_LINKID);
437843e1988Sjohnlev 
438da14cebeSEric Cheng 	if (!dladm_vnic_macaddrtype2str(mac_addr_type))
439843e1988Sjohnlev 		return (DLADM_STATUS_INVALIDMACADDRTYPE);
440843e1988Sjohnlev 
441da14cebeSEric Cheng 	if ((flags & DLADM_OPT_ANCHOR) == 0) {
4424ac67f02SAnurag S. Maskey 		if ((status = dladm_datalink_id2info(handle, linkid, NULL,
4434ac67f02SAnurag S. Maskey 		    &class, &media, NULL, 0)) != DLADM_STATUS_OK)
444da14cebeSEric Cheng 			return (status);
445da14cebeSEric Cheng 
446da14cebeSEric Cheng 		if (class == DATALINK_CLASS_VNIC ||
447da14cebeSEric Cheng 		    class == DATALINK_CLASS_VLAN)
448d62bc4baSyz147064 			return (DLADM_STATUS_BADARG);
449da14cebeSEric Cheng 	} else {
450da14cebeSEric Cheng 		/* it's an anchor VNIC */
451da14cebeSEric Cheng 		if (linkid != DATALINK_INVALID_LINKID || vid != 0)
452da14cebeSEric Cheng 			return (DLADM_STATUS_BADARG);
453da14cebeSEric Cheng 	}
454d62bc4baSyz147064 
455*1cb875aeSCathy Zhou 	/*
456*1cb875aeSCathy Zhou 	 * Only VRRP VNIC need VRID and address family specified.
457*1cb875aeSCathy Zhou 	 */
458*1cb875aeSCathy Zhou 	if (mac_addr_type != VNIC_MAC_ADDR_TYPE_VRID &&
459*1cb875aeSCathy Zhou 	    (af != AF_UNSPEC || vrid != VRRP_VRID_NONE)) {
460*1cb875aeSCathy Zhou 		return (DLADM_STATUS_BADARG);
461*1cb875aeSCathy Zhou 	}
462*1cb875aeSCathy Zhou 
463*1cb875aeSCathy Zhou 	/*
464*1cb875aeSCathy Zhou 	 * If a random address might be generated, but no prefix
465*1cb875aeSCathy Zhou 	 * was specified by the caller, use the default MAC address
466*1cb875aeSCathy Zhou 	 * prefix.
467*1cb875aeSCathy Zhou 	 */
468*1cb875aeSCathy Zhou 	if ((mac_addr_type == VNIC_MAC_ADDR_TYPE_RANDOM ||
469*1cb875aeSCathy Zhou 	    mac_addr_type == VNIC_MAC_ADDR_TYPE_AUTO) &&
470*1cb875aeSCathy Zhou 	    mac_prefix_len == 0) {
471*1cb875aeSCathy Zhou 		mac_prefix_len = sizeof (dladm_vnic_def_prefix);
472*1cb875aeSCathy Zhou 		mac_addr = tmp_addr;
473*1cb875aeSCathy Zhou 		bcopy(dladm_vnic_def_prefix, mac_addr, mac_prefix_len);
474*1cb875aeSCathy Zhou 	}
475*1cb875aeSCathy Zhou 
476*1cb875aeSCathy Zhou 	/*
477*1cb875aeSCathy Zhou 	 * If this is a VRRP VNIC, generate its MAC address using the given
478*1cb875aeSCathy Zhou 	 * VRID and address family.
479*1cb875aeSCathy Zhou 	 */
480*1cb875aeSCathy Zhou 	if (mac_addr_type == VNIC_MAC_ADDR_TYPE_VRID) {
481*1cb875aeSCathy Zhou 		/*
482*1cb875aeSCathy Zhou 		 * VRRP VNICs must be created over ethernet data-links.
483*1cb875aeSCathy Zhou 		 */
484*1cb875aeSCathy Zhou 		if (vrid < VRRP_VRID_MIN || vrid > VRRP_VRID_MAX ||
485*1cb875aeSCathy Zhou 		    (af != AF_INET && af != AF_INET6) || mac_addr != NULL ||
486*1cb875aeSCathy Zhou 		    mac_len != 0 || mac_prefix_len != 0 ||
487*1cb875aeSCathy Zhou 		    (mac_slot != NULL && *mac_slot != -1) || is_etherstub ||
488*1cb875aeSCathy Zhou 		    media != DL_ETHER) {
489*1cb875aeSCathy Zhou 			return (DLADM_STATUS_BADARG);
490*1cb875aeSCathy Zhou 		}
491*1cb875aeSCathy Zhou 		mac_len = ETHERADDRL;
492*1cb875aeSCathy Zhou 		mac_addr = tmp_addr;
493*1cb875aeSCathy Zhou 		status = i_dladm_vnic_vrrp_mac(vrid, af, mac_addr, mac_len);
494*1cb875aeSCathy Zhou 		if (status != DLADM_STATUS_OK)
495*1cb875aeSCathy Zhou 			return (status);
496*1cb875aeSCathy Zhou 	}
497*1cb875aeSCathy Zhou 
498*1cb875aeSCathy Zhou 	if (mac_len > MAXMACADDRLEN)
499*1cb875aeSCathy Zhou 		return (DLADM_STATUS_INVALIDMACADDRLEN);
500*1cb875aeSCathy Zhou 
501d62bc4baSyz147064 	if (vnic == NULL) {
502d62bc4baSyz147064 		flags |= DLADM_OPT_PREFIX;
503da14cebeSEric Cheng 		(void) strlcpy(name, "vnic", sizeof (name));
504da14cebeSEric Cheng 	} else {
505da14cebeSEric Cheng 		(void) strlcpy(name, vnic, sizeof (name));
506d62bc4baSyz147064 	}
507d62bc4baSyz147064 
508da14cebeSEric Cheng 	class = is_vlan ? DATALINK_CLASS_VLAN :
509da14cebeSEric Cheng 	    (is_etherstub ? DATALINK_CLASS_ETHERSTUB : DATALINK_CLASS_VNIC);
5104ac67f02SAnurag S. Maskey 	if ((status = dladm_create_datalink_id(handle, name, class,
511da14cebeSEric Cheng 	    media, flags, &vnic_id)) != DLADM_STATUS_OK)
512d62bc4baSyz147064 		return (status);
513da14cebeSEric Cheng 
514da14cebeSEric Cheng 	if ((flags & DLADM_OPT_PREFIX) != 0) {
515da14cebeSEric Cheng 		(void) snprintf(name + 4, sizeof (name), "%llu", vnic_id);
516da14cebeSEric Cheng 		flags &= ~DLADM_OPT_PREFIX;
517843e1988Sjohnlev 	}
518843e1988Sjohnlev 
519843e1988Sjohnlev 	bzero(&attr, sizeof (attr));
520843e1988Sjohnlev 
521da14cebeSEric Cheng 	/* Extract resource_ctl and cpu_list from proplist */
522da14cebeSEric Cheng 	if (proplist != NULL) {
5234ac67f02SAnurag S. Maskey 		status = dladm_link_proplist_extract(handle, proplist,
524da14cebeSEric Cheng 		    &attr.va_resource_props);
525da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK)
526d62bc4baSyz147064 			goto done;
527d62bc4baSyz147064 	}
528843e1988Sjohnlev 
529da14cebeSEric Cheng 	attr.va_vnic_id = vnic_id;
530da14cebeSEric Cheng 	attr.va_link_id = linkid;
531da14cebeSEric Cheng 	attr.va_mac_addr_type = mac_addr_type;
532da14cebeSEric Cheng 	attr.va_mac_len = mac_len;
533da14cebeSEric Cheng 	if (mac_slot != NULL)
534da14cebeSEric Cheng 		attr.va_mac_slot = *mac_slot;
535da14cebeSEric Cheng 	if (mac_len > 0)
536da14cebeSEric Cheng 		bcopy(mac_addr, attr.va_mac_addr, mac_len);
537da14cebeSEric Cheng 	else if (mac_prefix_len > 0)
538da14cebeSEric Cheng 		bcopy(mac_addr, attr.va_mac_addr, mac_prefix_len);
539da14cebeSEric Cheng 	attr.va_mac_prefix_len = mac_prefix_len;
540da14cebeSEric Cheng 	attr.va_vid = vid;
541*1cb875aeSCathy Zhou 	attr.va_vrid = vrid;
542*1cb875aeSCathy Zhou 	attr.va_af = af;
543da14cebeSEric Cheng 	attr.va_force = (flags & DLADM_OPT_FORCE) != 0;
544da14cebeSEric Cheng 	attr.va_hwrings = (flags & DLADM_OPT_HWRINGS) != 0;
545da14cebeSEric Cheng 
5464ac67f02SAnurag S. Maskey 	status = i_dladm_vnic_create_sys(handle, &attr);
547da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
548da14cebeSEric Cheng 		goto done;
5494eaa4710SRishi Srivatsavai 	vnic_created = B_TRUE;
550da14cebeSEric Cheng 
551da14cebeSEric Cheng 	/* Save vnic configuration and its properties */
552da14cebeSEric Cheng 	if (!(flags & DLADM_OPT_PERSIST))
553da14cebeSEric Cheng 		goto done;
554da14cebeSEric Cheng 
5554ac67f02SAnurag S. Maskey 	status = dladm_vnic_persist_conf(handle, name, &attr, class);
5564eaa4710SRishi Srivatsavai 	if (status != DLADM_STATUS_OK)
557da14cebeSEric Cheng 		goto done;
5584eaa4710SRishi Srivatsavai 	conf_set = B_TRUE;
559da14cebeSEric Cheng 
560da14cebeSEric Cheng 	if (proplist != NULL) {
561da14cebeSEric Cheng 		for (i = 0; i < proplist->al_count; i++) {
562da14cebeSEric Cheng 			dladm_arg_info_t	*aip = &proplist->al_info[i];
563da14cebeSEric Cheng 
5644ac67f02SAnurag S. Maskey 			status = dladm_set_linkprop(handle, vnic_id,
5654ac67f02SAnurag S. Maskey 			    aip->ai_name, aip->ai_val, aip->ai_count,
5664ac67f02SAnurag S. Maskey 			    DLADM_OPT_PERSIST);
567da14cebeSEric Cheng 			if (status != DLADM_STATUS_OK)
568da14cebeSEric Cheng 				break;
569da14cebeSEric Cheng 		}
570da14cebeSEric Cheng 	}
571843e1988Sjohnlev 
572d62bc4baSyz147064 done:
573d62bc4baSyz147064 	if (status != DLADM_STATUS_OK) {
5744eaa4710SRishi Srivatsavai 		if (conf_set)
5754eaa4710SRishi Srivatsavai 			(void) dladm_remove_conf(handle, vnic_id);
5764eaa4710SRishi Srivatsavai 		if (vnic_created)
5774eaa4710SRishi Srivatsavai 			(void) i_dladm_vnic_delete_sys(handle, vnic_id);
5784ac67f02SAnurag S. Maskey 		(void) dladm_destroy_datalink_id(handle, vnic_id, flags);
579d62bc4baSyz147064 	} else {
580da14cebeSEric Cheng 		if (vnic_id_out != NULL)
581d62bc4baSyz147064 			*vnic_id_out = vnic_id;
582da14cebeSEric Cheng 		if (mac_slot != NULL)
583da14cebeSEric Cheng 			*mac_slot = attr.va_mac_slot;
584d62bc4baSyz147064 	}
5854eaa4710SRishi Srivatsavai 
5864eaa4710SRishi Srivatsavai 	if (is_vlan) {
5874eaa4710SRishi Srivatsavai 		dladm_status_t stat2;
5884eaa4710SRishi Srivatsavai 
5894eaa4710SRishi Srivatsavai 		stat2 = dladm_bridge_refresh(handle, linkid);
5904eaa4710SRishi Srivatsavai 		if (status == DLADM_STATUS_OK && stat2 != DLADM_STATUS_OK)
5914eaa4710SRishi Srivatsavai 			status = stat2;
5924eaa4710SRishi Srivatsavai 	}
593843e1988Sjohnlev 	return (status);
594843e1988Sjohnlev }
595843e1988Sjohnlev 
596843e1988Sjohnlev /*
597da14cebeSEric Cheng  * Delete a VNIC / VLAN.
598843e1988Sjohnlev  */
599843e1988Sjohnlev dladm_status_t
6004ac67f02SAnurag S. Maskey dladm_vnic_delete(dladm_handle_t handle, datalink_id_t linkid, uint32_t flags)
601843e1988Sjohnlev {
602d62bc4baSyz147064 	dladm_status_t status;
603da14cebeSEric Cheng 	datalink_class_t class;
604843e1988Sjohnlev 
605da14cebeSEric Cheng 	if (flags == 0)
606da14cebeSEric Cheng 		return (DLADM_STATUS_BADARG);
607843e1988Sjohnlev 
6084ac67f02SAnurag S. Maskey 	if ((dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, NULL, 0)
6094ac67f02SAnurag S. Maskey 	    != DLADM_STATUS_OK))
610da14cebeSEric Cheng 		return (DLADM_STATUS_BADARG);
611d62bc4baSyz147064 
612da14cebeSEric Cheng 	if ((flags & DLADM_OPT_VLAN) != 0) {
613da14cebeSEric Cheng 		if (class != DATALINK_CLASS_VLAN)
614da14cebeSEric Cheng 			return (DLADM_STATUS_BADARG);
615da14cebeSEric Cheng 	} else {
616da14cebeSEric Cheng 		if (class != DATALINK_CLASS_VNIC &&
617da14cebeSEric Cheng 		    class != DATALINK_CLASS_ETHERSTUB)
618da14cebeSEric Cheng 			return (DLADM_STATUS_BADARG);
619da14cebeSEric Cheng 	}
620d62bc4baSyz147064 
621da14cebeSEric Cheng 	if ((flags & DLADM_OPT_ACTIVE) != 0) {
6224ac67f02SAnurag S. Maskey 		status = i_dladm_vnic_delete_sys(handle, linkid);
623da14cebeSEric Cheng 		if (status == DLADM_STATUS_OK) {
6244ac67f02SAnurag S. Maskey 			(void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0,
625da14cebeSEric Cheng 			    DLADM_OPT_ACTIVE);
6264ac67f02SAnurag S. Maskey 			(void) dladm_destroy_datalink_id(handle, linkid,
627da14cebeSEric Cheng 			    DLADM_OPT_ACTIVE);
628da14cebeSEric Cheng 		} else if (status != DLADM_STATUS_NOTFOUND ||
629da14cebeSEric Cheng 		    !(flags & DLADM_OPT_PERSIST)) {
630da14cebeSEric Cheng 			return (status);
631da14cebeSEric Cheng 		}
632da14cebeSEric Cheng 	}
633da14cebeSEric Cheng 	if ((flags & DLADM_OPT_PERSIST) != 0) {
6342b24ab6bSSebastien Roy 		(void) dladm_remove_conf(handle, linkid);
6354ac67f02SAnurag S. Maskey 		(void) dladm_destroy_datalink_id(handle, linkid,
6364ac67f02SAnurag S. Maskey 		    DLADM_OPT_PERSIST);
637da14cebeSEric Cheng 	}
6384eaa4710SRishi Srivatsavai 	return (dladm_bridge_refresh(handle, linkid));
639da14cebeSEric Cheng }
640da14cebeSEric Cheng 
641da14cebeSEric Cheng static const char *
642da14cebeSEric Cheng dladm_vnic_macaddr2str(const uchar_t *mac, char *buf)
643da14cebeSEric Cheng {
644da14cebeSEric Cheng 	static char unknown_mac[] = {0, 0, 0, 0, 0, 0};
645da14cebeSEric Cheng 
646da14cebeSEric Cheng 	if (buf == NULL)
647da14cebeSEric Cheng 		return (NULL);
648da14cebeSEric Cheng 
649da14cebeSEric Cheng 	if (bcmp(unknown_mac, mac, ETHERADDRL) == 0)
650da14cebeSEric Cheng 		(void) strlcpy(buf, "unknown", DLADM_STRSIZE);
651da14cebeSEric Cheng 	else
652da14cebeSEric Cheng 		return (_link_ntoa(mac, buf, ETHERADDRL, IFT_OTHER));
653da14cebeSEric Cheng 
654da14cebeSEric Cheng 	return (buf);
655da14cebeSEric Cheng }
656da14cebeSEric Cheng 
657da14cebeSEric Cheng static dladm_status_t
658da14cebeSEric Cheng dladm_vnic_str2macaddr(const char *str, uchar_t *buf)
659da14cebeSEric Cheng {
660da14cebeSEric Cheng 	int len = 0;
661da14cebeSEric Cheng 	uchar_t *b = _link_aton(str, &len);
662da14cebeSEric Cheng 
663da14cebeSEric Cheng 	if (b == NULL || len >= MAXMACADDRLEN)
664da14cebeSEric Cheng 		return (DLADM_STATUS_BADARG);
665da14cebeSEric Cheng 
666da14cebeSEric Cheng 	bcopy(b, buf, len);
667da14cebeSEric Cheng 	free(b);
668da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
669da14cebeSEric Cheng }
670da14cebeSEric Cheng 
671da14cebeSEric Cheng 
672da14cebeSEric Cheng static dladm_status_t
6734ac67f02SAnurag S. Maskey dladm_vnic_persist_conf(dladm_handle_t handle, const char *name,
6744ac67f02SAnurag S. Maskey     dladm_vnic_attr_t *attrp, datalink_class_t class)
675da14cebeSEric Cheng {
676da14cebeSEric Cheng 	dladm_conf_t conf = DLADM_INVALID_CONF;
677da14cebeSEric Cheng 	dladm_status_t status;
678da14cebeSEric Cheng 	char macstr[ETHERADDRL * 3];
6792b24ab6bSSebastien Roy 	char linkover[MAXLINKNAMELEN];
680da14cebeSEric Cheng 	uint64_t u64;
681da14cebeSEric Cheng 
6824ac67f02SAnurag S. Maskey 	if ((status = dladm_create_conf(handle, name, attrp->va_vnic_id,
683da14cebeSEric Cheng 	    class, DL_ETHER, &conf)) != DLADM_STATUS_OK)
684da14cebeSEric Cheng 		return (status);
685da14cebeSEric Cheng 
686da14cebeSEric Cheng 	if (attrp->va_link_id != DATALINK_INVALID_LINKID) {
6872b24ab6bSSebastien Roy 		status = dladm_datalink_id2info(handle, attrp->va_link_id, NULL,
6882b24ab6bSSebastien Roy 		    NULL, NULL, linkover, sizeof (linkover));
6892b24ab6bSSebastien Roy 		if (status != DLADM_STATUS_OK)
6902b24ab6bSSebastien Roy 			goto done;
6914ac67f02SAnurag S. Maskey 		status = dladm_set_conf_field(handle, conf, FLINKOVER,
6922b24ab6bSSebastien Roy 		    DLADM_TYPE_STR, linkover);
693d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
694da14cebeSEric Cheng 			goto done;
695da14cebeSEric Cheng 	}
696d62bc4baSyz147064 
697da14cebeSEric Cheng 	if (class != DATALINK_CLASS_VLAN) {
698da14cebeSEric Cheng 		u64 = attrp->va_mac_addr_type;
6994ac67f02SAnurag S. Maskey 		status = dladm_set_conf_field(handle, conf, FMADDRTYPE,
700da14cebeSEric Cheng 		    DLADM_TYPE_UINT64, &u64);
701da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK)
702da14cebeSEric Cheng 			goto done;
703da14cebeSEric Cheng 
704*1cb875aeSCathy Zhou 		u64 = attrp->va_vrid;
705*1cb875aeSCathy Zhou 		status = dladm_set_conf_field(handle, conf, FVRID,
706*1cb875aeSCathy Zhou 		    DLADM_TYPE_UINT64, &u64);
707*1cb875aeSCathy Zhou 		if (status != DLADM_STATUS_OK)
708*1cb875aeSCathy Zhou 			goto done;
709*1cb875aeSCathy Zhou 
710*1cb875aeSCathy Zhou 		u64 = attrp->va_af;
711*1cb875aeSCathy Zhou 		status = dladm_set_conf_field(handle, conf, FVRAF,
712*1cb875aeSCathy Zhou 		    DLADM_TYPE_UINT64, &u64);
713*1cb875aeSCathy Zhou 		if (status != DLADM_STATUS_OK)
714*1cb875aeSCathy Zhou 			goto done;
715*1cb875aeSCathy Zhou 
716da14cebeSEric Cheng 		if (attrp->va_mac_len != ETHERADDRL) {
717da14cebeSEric Cheng 			u64 = attrp->va_mac_len;
7184ac67f02SAnurag S. Maskey 			status = dladm_set_conf_field(handle, conf, FMADDRLEN,
719da14cebeSEric Cheng 			    DLADM_TYPE_UINT64, &u64);
720da14cebeSEric Cheng 			if (status != DLADM_STATUS_OK)
721da14cebeSEric Cheng 				goto done;
722da14cebeSEric Cheng 		}
723da14cebeSEric Cheng 
724da14cebeSEric Cheng 		if (attrp->va_mac_slot != -1) {
725da14cebeSEric Cheng 			u64 = attrp->va_mac_slot;
726*1cb875aeSCathy Zhou 			status = dladm_set_conf_field(handle, conf,
727*1cb875aeSCathy Zhou 			    FMADDRSLOT, DLADM_TYPE_UINT64, &u64);
728da14cebeSEric Cheng 			if (status != DLADM_STATUS_OK)
729da14cebeSEric Cheng 			goto done;
730da14cebeSEric Cheng 		}
731da14cebeSEric Cheng 
732da14cebeSEric Cheng 		if (attrp->va_mac_prefix_len !=
733da14cebeSEric Cheng 		    sizeof (dladm_vnic_def_prefix)) {
734da14cebeSEric Cheng 			u64 = attrp->va_mac_prefix_len;
7354ac67f02SAnurag S. Maskey 			status = dladm_set_conf_field(handle, conf,
7364ac67f02SAnurag S. Maskey 			    FMADDRPREFIXLEN, DLADM_TYPE_UINT64, &u64);
737da14cebeSEric Cheng 			if (status != DLADM_STATUS_OK)
738da14cebeSEric Cheng 				goto done;
739da14cebeSEric Cheng 		}
740da14cebeSEric Cheng 
741da14cebeSEric Cheng 		(void) dladm_vnic_macaddr2str(attrp->va_mac_addr, macstr);
7424ac67f02SAnurag S. Maskey 		status = dladm_set_conf_field(handle, conf, FMACADDR,
7434ac67f02SAnurag S. Maskey 		    DLADM_TYPE_STR, macstr);
744da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK)
745da14cebeSEric Cheng 			goto done;
746da14cebeSEric Cheng 	}
747da14cebeSEric Cheng 
748*1cb875aeSCathy Zhou 	if (attrp->va_hwrings) {
749*1cb875aeSCathy Zhou 		boolean_t hwrings = attrp->va_hwrings;
750*1cb875aeSCathy Zhou 		status = dladm_set_conf_field(handle, conf, FHWRINGS,
751*1cb875aeSCathy Zhou 		    DLADM_TYPE_BOOLEAN, &hwrings);
752*1cb875aeSCathy Zhou 		if (status != DLADM_STATUS_OK)
753*1cb875aeSCathy Zhou 			goto done;
754*1cb875aeSCathy Zhou 	}
755*1cb875aeSCathy Zhou 
756da14cebeSEric Cheng 	if (attrp->va_vid != 0) {
757da14cebeSEric Cheng 		u64 = attrp->va_vid;
7584ac67f02SAnurag S. Maskey 		status = dladm_set_conf_field(handle, conf, FVLANID,
759da14cebeSEric Cheng 		    DLADM_TYPE_UINT64, &u64);
760da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK)
761da14cebeSEric Cheng 			goto done;
762da14cebeSEric Cheng 	}
763da14cebeSEric Cheng 
764da14cebeSEric Cheng 	/*
765da14cebeSEric Cheng 	 * Commit the link configuration.
766da14cebeSEric Cheng 	 */
7674ac67f02SAnurag S. Maskey 	status = dladm_write_conf(handle, conf);
768da14cebeSEric Cheng 
769da14cebeSEric Cheng done:
7704ac67f02SAnurag S. Maskey 	dladm_destroy_conf(handle, conf);
771d62bc4baSyz147064 	return (status);
772843e1988Sjohnlev }
773da14cebeSEric Cheng 
774da14cebeSEric Cheng typedef struct dladm_vnic_up_arg_s {
775da14cebeSEric Cheng 	uint32_t	flags;
776da14cebeSEric Cheng 	dladm_status_t	status;
777da14cebeSEric Cheng } dladm_vnic_up_arg_t;
778da14cebeSEric Cheng 
779da14cebeSEric Cheng #define	DLADM_VNIC_UP_FIRST_WALK	0x1
780da14cebeSEric Cheng #define	DLADM_VNIC_UP_SECOND_WALK	0x2
781da14cebeSEric Cheng 
782da14cebeSEric Cheng static int
7834ac67f02SAnurag S. Maskey i_dladm_vnic_up(dladm_handle_t handle, datalink_id_t linkid, void *arg)
784da14cebeSEric Cheng {
785da14cebeSEric Cheng 	dladm_status_t *statusp = &(((dladm_vnic_up_arg_t *)arg)->status);
786da14cebeSEric Cheng 	dladm_vnic_attr_t attr;
787da14cebeSEric Cheng 	dladm_status_t status;
788da14cebeSEric Cheng 	dladm_arg_list_t *proplist;
789da14cebeSEric Cheng 	uint32_t flags = ((dladm_vnic_up_arg_t *)arg)->flags;
790da14cebeSEric Cheng 
791da14cebeSEric Cheng 	bzero(&attr, sizeof (attr));
792da14cebeSEric Cheng 
7934ac67f02SAnurag S. Maskey 	status = dladm_vnic_info(handle, linkid, &attr, DLADM_OPT_PERSIST);
794da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
795da14cebeSEric Cheng 		goto done;
796da14cebeSEric Cheng 
797da14cebeSEric Cheng 	/*
798da14cebeSEric Cheng 	 * Create the vnics that request hardware group first
799da14cebeSEric Cheng 	 * Create the vnics that don't request hardware group in the second walk
800da14cebeSEric Cheng 	 */
801da14cebeSEric Cheng 	if ((flags == DLADM_VNIC_UP_FIRST_WALK && !attr.va_hwrings) ||
802da14cebeSEric Cheng 	    (flags == DLADM_VNIC_UP_SECOND_WALK && attr.va_hwrings))
803da14cebeSEric Cheng 			goto done;
804da14cebeSEric Cheng 
805da14cebeSEric Cheng 	/* Get all properties for this vnic */
8064ac67f02SAnurag S. Maskey 	status = dladm_link_get_proplist(handle, linkid, &proplist);
807da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
808da14cebeSEric Cheng 		goto done;
809da14cebeSEric Cheng 
810da14cebeSEric Cheng 	if (proplist != NULL) {
8114ac67f02SAnurag S. Maskey 		status = dladm_link_proplist_extract(handle, proplist,
812da14cebeSEric Cheng 		    &attr.va_resource_props);
813da14cebeSEric Cheng 	}
814da14cebeSEric Cheng 
8154ac67f02SAnurag S. Maskey 	status = i_dladm_vnic_create_sys(handle, &attr);
8164eaa4710SRishi Srivatsavai 	if (status == DLADM_STATUS_OK) {
8174eaa4710SRishi Srivatsavai 		status = dladm_up_datalink_id(handle, linkid);
818da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK)
8194ac67f02SAnurag S. Maskey 			(void) i_dladm_vnic_delete_sys(handle, linkid);
820da14cebeSEric Cheng 	}
8214eaa4710SRishi Srivatsavai 
822da14cebeSEric Cheng done:
823da14cebeSEric Cheng 	*statusp = status;
824da14cebeSEric Cheng 	return (DLADM_WALK_CONTINUE);
825da14cebeSEric Cheng }
826da14cebeSEric Cheng 
827da14cebeSEric Cheng dladm_status_t
8284ac67f02SAnurag S. Maskey dladm_vnic_up(dladm_handle_t handle, datalink_id_t linkid, uint32_t flags)
829da14cebeSEric Cheng {
830da14cebeSEric Cheng 	dladm_vnic_up_arg_t vnic_arg;
831da14cebeSEric Cheng 	datalink_class_t class;
832da14cebeSEric Cheng 
833da14cebeSEric Cheng 	class = ((flags & DLADM_OPT_VLAN) != 0) ? DATALINK_CLASS_VLAN :
834da14cebeSEric Cheng 	    (DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB);
835da14cebeSEric Cheng 
836da14cebeSEric Cheng 	if (linkid == DATALINK_ALL_LINKID) {
837da14cebeSEric Cheng 		vnic_arg.flags = DLADM_VNIC_UP_FIRST_WALK;
8384ac67f02SAnurag S. Maskey 		(void) dladm_walk_datalink_id(i_dladm_vnic_up, handle,
8394ac67f02SAnurag S. Maskey 		    &vnic_arg, class, DATALINK_ANY_MEDIATYPE,
8404ac67f02SAnurag S. Maskey 		    DLADM_OPT_PERSIST);
841da14cebeSEric Cheng 		vnic_arg.flags = DLADM_VNIC_UP_SECOND_WALK;
8424ac67f02SAnurag S. Maskey 		(void) dladm_walk_datalink_id(i_dladm_vnic_up, handle,
8434ac67f02SAnurag S. Maskey 		    &vnic_arg, class, DATALINK_ANY_MEDIATYPE,
8444ac67f02SAnurag S. Maskey 		    DLADM_OPT_PERSIST);
845da14cebeSEric Cheng 		return (DLADM_STATUS_OK);
846da14cebeSEric Cheng 	} else {
8474ac67f02SAnurag S. Maskey 		(void) i_dladm_vnic_up(handle, linkid, &vnic_arg);
848da14cebeSEric Cheng 		return (vnic_arg.status);
849da14cebeSEric Cheng 	}
850da14cebeSEric Cheng }
851