xref: /titanic_44/usr/src/lib/libdladm/common/libdlvnic.c (revision da14cebe459d3275048785f25bd869cb09b5307f)
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 /*
22d62bc4baSyz147064  * Copyright 2008 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>
39*da14cebeSEric Cheng #include <sys/dld.h>
40843e1988Sjohnlev #include <libdladm_impl.h>
41d62bc4baSyz147064 #include <libdllink.h>
42843e1988Sjohnlev #include <libdlvnic.h>
43843e1988Sjohnlev 
44843e1988Sjohnlev /*
45843e1988Sjohnlev  * VNIC administration library.
46843e1988Sjohnlev  */
47843e1988Sjohnlev 
48*da14cebeSEric Cheng /*
49*da14cebeSEric Cheng  * Default random MAC address prefix (locally administered).
50*da14cebeSEric Cheng  */
51*da14cebeSEric Cheng static char dladm_vnic_def_prefix[] = {0x02, 0x08, 0x20};
52843e1988Sjohnlev 
53*da14cebeSEric Cheng static dladm_status_t	dladm_vnic_persist_conf(const char *name,
54*da14cebeSEric Cheng 			    dladm_vnic_attr_t *, datalink_class_t);
55*da14cebeSEric Cheng static const char	*dladm_vnic_macaddr2str(const uchar_t *, char *);
56*da14cebeSEric Cheng static dladm_status_t	dladm_vnic_str2macaddr(const char *, uchar_t *);
57843e1988Sjohnlev 
58843e1988Sjohnlev /*
59*da14cebeSEric Cheng  * Convert a diagnostic returned by the kernel into a dladm_status_t.
60843e1988Sjohnlev  */
61843e1988Sjohnlev static dladm_status_t
62*da14cebeSEric Cheng dladm_vnic_diag2status(vnic_ioc_diag_t ioc_diag)
63843e1988Sjohnlev {
64*da14cebeSEric Cheng 	switch (ioc_diag) {
65*da14cebeSEric Cheng 	case VNIC_IOC_DIAG_MACADDR_INVALID:
66*da14cebeSEric Cheng 		return (DLADM_STATUS_INVALIDMACADDR);
67*da14cebeSEric Cheng 	case VNIC_IOC_DIAG_MACADDRLEN_INVALID:
68*da14cebeSEric Cheng 		return (DLADM_STATUS_INVALIDMACADDRLEN);
69*da14cebeSEric Cheng 	case VNIC_IOC_DIAG_MACADDR_NIC:
70*da14cebeSEric Cheng 		return (DLADM_STATUS_INVALIDMACADDRNIC);
71*da14cebeSEric Cheng 	case VNIC_IOC_DIAG_MACADDR_INUSE:
72*da14cebeSEric Cheng 		return (DLADM_STATUS_INVALIDMACADDRINUSE);
73*da14cebeSEric Cheng 	case VNIC_IOC_DIAG_MACFACTORYSLOTINVALID:
74*da14cebeSEric Cheng 		return (DLADM_STATUS_MACFACTORYSLOTINVALID);
75*da14cebeSEric Cheng 	case VNIC_IOC_DIAG_MACFACTORYSLOTUSED:
76*da14cebeSEric Cheng 		return (DLADM_STATUS_MACFACTORYSLOTUSED);
77*da14cebeSEric Cheng 	case VNIC_IOC_DIAG_MACFACTORYSLOTALLUSED:
78*da14cebeSEric Cheng 		return (DLADM_STATUS_MACFACTORYSLOTALLUSED);
79*da14cebeSEric Cheng 	case VNIC_IOC_DIAG_MACFACTORYNOTSUP:
80*da14cebeSEric Cheng 		return (DLADM_STATUS_MACFACTORYNOTSUP);
81*da14cebeSEric Cheng 	case VNIC_IOC_DIAG_MACPREFIX_INVALID:
82*da14cebeSEric Cheng 		return (DLADM_STATUS_INVALIDMACPREFIX);
83*da14cebeSEric Cheng 	case VNIC_IOC_DIAG_MACPREFIXLEN_INVALID:
84*da14cebeSEric Cheng 		return (DLADM_STATUS_INVALIDMACPREFIXLEN);
85*da14cebeSEric Cheng 	case VNIC_IOC_DIAG_MACMARGIN_INVALID:
86*da14cebeSEric Cheng 		return (DLADM_STATUS_INVALID_MACMARGIN);
87*da14cebeSEric Cheng 	case VNIC_IOC_DIAG_NO_HWRINGS:
88*da14cebeSEric Cheng 		return (DLADM_STATUS_NO_HWRINGS);
89*da14cebeSEric Cheng 	}
90843e1988Sjohnlev 	return (DLADM_STATUS_OK);
91843e1988Sjohnlev }
92843e1988Sjohnlev 
93843e1988Sjohnlev /*
94*da14cebeSEric Cheng  * Send a create command to the VNIC driver.
95843e1988Sjohnlev  */
96*da14cebeSEric Cheng dladm_status_t
97*da14cebeSEric Cheng i_dladm_vnic_create_sys(dladm_vnic_attr_t *attr)
98843e1988Sjohnlev {
99*da14cebeSEric Cheng 	int rc, fd;
100*da14cebeSEric Cheng 	vnic_ioc_create_t ioc;
101eae72b5bSSebastien Roy 	dladm_status_t status = DLADM_STATUS_OK;
102843e1988Sjohnlev 
103*da14cebeSEric Cheng 	bzero(&ioc, sizeof (ioc));
104*da14cebeSEric Cheng 	ioc.vc_vnic_id = attr->va_vnic_id;
105*da14cebeSEric Cheng 	ioc.vc_link_id = attr->va_link_id;
106*da14cebeSEric Cheng 	ioc.vc_mac_addr_type = attr->va_mac_addr_type;
107*da14cebeSEric Cheng 	ioc.vc_mac_len = attr->va_mac_len;
108*da14cebeSEric Cheng 	ioc.vc_mac_slot = attr->va_mac_slot;
109*da14cebeSEric Cheng 	ioc.vc_mac_prefix_len = attr->va_mac_prefix_len;
110*da14cebeSEric Cheng 	ioc.vc_vid = attr->va_vid;
111*da14cebeSEric Cheng 	ioc.vc_flags = attr->va_force ? VNIC_IOC_CREATE_FORCE : 0;
112*da14cebeSEric Cheng 	ioc.vc_flags |= attr->va_hwrings ? VNIC_IOC_CREATE_REQ_HWRINGS : 0;
113843e1988Sjohnlev 
114*da14cebeSEric Cheng 	if (attr->va_mac_len > 0 || ioc.vc_mac_prefix_len > 0)
115*da14cebeSEric Cheng 		bcopy(attr->va_mac_addr, ioc.vc_mac_addr, MAXMACADDRLEN);
116*da14cebeSEric Cheng 	bcopy(&attr->va_resource_props, &ioc.vc_resource_props,
117*da14cebeSEric Cheng 	    sizeof (mac_resource_props_t));
118*da14cebeSEric Cheng 	if (attr->va_link_id == DATALINK_INVALID_LINKID)
119*da14cebeSEric Cheng 		ioc.vc_flags |= VNIC_IOC_CREATE_ANCHOR;
120843e1988Sjohnlev 
121eae72b5bSSebastien Roy 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
122843e1988Sjohnlev 		return (dladm_errno2status(errno));
123843e1988Sjohnlev 
124*da14cebeSEric Cheng 	rc = ioctl(fd, VNIC_IOC_CREATE, &ioc);
125*da14cebeSEric Cheng 	if (rc < 0)
126eae72b5bSSebastien Roy 		status = dladm_errno2status(errno);
127843e1988Sjohnlev 
128843e1988Sjohnlev 	(void) close(fd);
129*da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK) {
130*da14cebeSEric Cheng 		if (ioc.vc_diag != VNIC_IOC_DIAG_NONE)
131*da14cebeSEric Cheng 			status = dladm_vnic_diag2status(ioc.vc_diag);
132*da14cebeSEric Cheng 	}
133*da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
134*da14cebeSEric Cheng 		return (status);
135*da14cebeSEric Cheng 
136*da14cebeSEric Cheng 	attr->va_mac_addr_type = ioc.vc_mac_addr_type;
137*da14cebeSEric Cheng 	switch (ioc.vc_mac_addr_type) {
138*da14cebeSEric Cheng 	case VNIC_MAC_ADDR_TYPE_FACTORY:
139*da14cebeSEric Cheng 		attr->va_mac_slot = ioc.vc_mac_slot;
140*da14cebeSEric Cheng 		break;
141*da14cebeSEric Cheng 	case VNIC_MAC_ADDR_TYPE_RANDOM:
142*da14cebeSEric Cheng 		bcopy(ioc.vc_mac_addr, attr->va_mac_addr, MAXMACADDRLEN);
143*da14cebeSEric Cheng 		attr->va_mac_len = ioc.vc_mac_len;
144*da14cebeSEric Cheng 		break;
145*da14cebeSEric Cheng 	}
146eae72b5bSSebastien Roy 	return (status);
147843e1988Sjohnlev }
148843e1988Sjohnlev 
149843e1988Sjohnlev /*
150d62bc4baSyz147064  * Get the configuration information of the given VNIC.
151843e1988Sjohnlev  */
152*da14cebeSEric Cheng static dladm_status_t
153*da14cebeSEric Cheng i_dladm_vnic_info_active(datalink_id_t linkid, dladm_vnic_attr_t *attrp)
154843e1988Sjohnlev {
155*da14cebeSEric Cheng 	vnic_ioc_info_t ioc;
156*da14cebeSEric Cheng 	vnic_info_t *vnic;
157*da14cebeSEric Cheng 	int rc, fd;
158843e1988Sjohnlev 	dladm_status_t status = DLADM_STATUS_OK;
159843e1988Sjohnlev 
160eae72b5bSSebastien Roy 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) == -1)
161843e1988Sjohnlev 		return (dladm_errno2status(errno));
162843e1988Sjohnlev 
163*da14cebeSEric Cheng 	bzero(&ioc, sizeof (ioc));
164*da14cebeSEric Cheng 	vnic = &ioc.vi_info;
165*da14cebeSEric Cheng 	vnic->vn_vnic_id = linkid;
166843e1988Sjohnlev 
167*da14cebeSEric Cheng 	rc = ioctl(fd, VNIC_IOC_INFO, &ioc);
168*da14cebeSEric Cheng 	if (rc != 0) {
169843e1988Sjohnlev 		status = dladm_errno2status(errno);
170843e1988Sjohnlev 		goto bail;
171843e1988Sjohnlev 	}
172843e1988Sjohnlev 
173d62bc4baSyz147064 	attrp->va_vnic_id = vnic->vn_vnic_id;
174d62bc4baSyz147064 	attrp->va_link_id = vnic->vn_link_id;
175d62bc4baSyz147064 	attrp->va_mac_addr_type = vnic->vn_mac_addr_type;
176*da14cebeSEric Cheng 	bcopy(vnic->vn_mac_addr, attrp->va_mac_addr, MAXMACADDRLEN);
177d62bc4baSyz147064 	attrp->va_mac_len = vnic->vn_mac_len;
178*da14cebeSEric Cheng 	attrp->va_mac_slot = vnic->vn_mac_slot;
179*da14cebeSEric Cheng 	attrp->va_mac_prefix_len = vnic->vn_mac_prefix_len;
180*da14cebeSEric Cheng 	attrp->va_vid = vnic->vn_vid;
181*da14cebeSEric Cheng 	attrp->va_force = vnic->vn_force;
182843e1988Sjohnlev 
183843e1988Sjohnlev bail:
184843e1988Sjohnlev 	(void) close(fd);
185843e1988Sjohnlev 	return (status);
186843e1988Sjohnlev }
187843e1988Sjohnlev 
188*da14cebeSEric Cheng static dladm_status_t
189*da14cebeSEric Cheng i_dladm_vnic_info_persist(datalink_id_t linkid, dladm_vnic_attr_t *attrp)
190*da14cebeSEric Cheng {
191*da14cebeSEric Cheng 	dladm_conf_t conf;
192*da14cebeSEric Cheng 	dladm_status_t status;
193*da14cebeSEric Cheng 	char macstr[ETHERADDRL * 3];
194*da14cebeSEric Cheng 	uint64_t u64;
195*da14cebeSEric Cheng 	datalink_class_t class;
196*da14cebeSEric Cheng 
197*da14cebeSEric Cheng 	attrp->va_vnic_id = linkid;
198*da14cebeSEric Cheng 	if ((status = dladm_read_conf(linkid, &conf)) != DLADM_STATUS_OK)
199*da14cebeSEric Cheng 		return (status);
200*da14cebeSEric Cheng 
201*da14cebeSEric Cheng 	status = dladm_get_conf_field(conf, FLINKOVER, &u64, sizeof (u64));
202*da14cebeSEric Cheng 	attrp->va_link_id = ((status == DLADM_STATUS_OK) ?
203*da14cebeSEric Cheng 	    (datalink_id_t)u64 : DATALINK_INVALID_LINKID);
204*da14cebeSEric Cheng 
205*da14cebeSEric Cheng 	status = dladm_get_conf_field(conf, FHWRINGS, &attrp->va_hwrings,
206*da14cebeSEric Cheng 	    sizeof (boolean_t));
207*da14cebeSEric Cheng 
208*da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK && status != DLADM_STATUS_NOTFOUND)
209*da14cebeSEric Cheng 		goto done;
210*da14cebeSEric Cheng 	if (status == DLADM_STATUS_NOTFOUND)
211*da14cebeSEric Cheng 		attrp->va_hwrings = B_FALSE;
212*da14cebeSEric Cheng 
213*da14cebeSEric Cheng 	if ((status = dladm_datalink_id2info(linkid, NULL, &class,
214*da14cebeSEric Cheng 	    NULL, NULL, 0)) != DLADM_STATUS_OK)
215*da14cebeSEric Cheng 		goto done;
216*da14cebeSEric Cheng 
217*da14cebeSEric Cheng 	if (class == DATALINK_CLASS_VLAN) {
218*da14cebeSEric Cheng 		if (attrp->va_link_id == DATALINK_INVALID_LINKID) {
219*da14cebeSEric Cheng 			status = DLADM_STATUS_BADARG;
220*da14cebeSEric Cheng 			goto done;
221*da14cebeSEric Cheng 		}
222*da14cebeSEric Cheng 		attrp->va_mac_addr_type = VNIC_MAC_ADDR_TYPE_PRIMARY;
223*da14cebeSEric Cheng 		attrp->va_mac_len = 0;
224*da14cebeSEric Cheng 	} else {
225*da14cebeSEric Cheng 		status = dladm_get_conf_field(conf, FMADDRTYPE, &u64,
226*da14cebeSEric Cheng 		    sizeof (u64));
227*da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK)
228*da14cebeSEric Cheng 			goto done;
229*da14cebeSEric Cheng 
230*da14cebeSEric Cheng 		attrp->va_mac_addr_type = (vnic_mac_addr_type_t)u64;
231*da14cebeSEric Cheng 
232*da14cebeSEric Cheng 		status = dladm_get_conf_field(conf, FMADDRLEN, &u64,
233*da14cebeSEric Cheng 		    sizeof (u64));
234*da14cebeSEric Cheng 		attrp->va_mac_len = ((status == DLADM_STATUS_OK) ?
235*da14cebeSEric Cheng 		    (uint_t)u64 : ETHERADDRL);
236*da14cebeSEric Cheng 
237*da14cebeSEric Cheng 		status = dladm_get_conf_field(conf, FMADDRSLOT, &u64,
238*da14cebeSEric Cheng 		    sizeof (u64));
239*da14cebeSEric Cheng 		attrp->va_mac_slot = ((status == DLADM_STATUS_OK) ?
240*da14cebeSEric Cheng 		    (int)u64 : -1);
241*da14cebeSEric Cheng 
242*da14cebeSEric Cheng 		status = dladm_get_conf_field(conf, FMADDRPREFIXLEN, &u64,
243*da14cebeSEric Cheng 		    sizeof (u64));
244*da14cebeSEric Cheng 		attrp->va_mac_prefix_len = ((status == DLADM_STATUS_OK) ?
245*da14cebeSEric Cheng 		    (uint_t)u64 : sizeof (dladm_vnic_def_prefix));
246*da14cebeSEric Cheng 
247*da14cebeSEric Cheng 		status = dladm_get_conf_field(conf, FMACADDR, macstr,
248*da14cebeSEric Cheng 		    sizeof (macstr));
249*da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK)
250*da14cebeSEric Cheng 			goto done;
251*da14cebeSEric Cheng 
252*da14cebeSEric Cheng 		status = dladm_vnic_str2macaddr(macstr, attrp->va_mac_addr);
253*da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK)
254*da14cebeSEric Cheng 			goto done;
255*da14cebeSEric Cheng 	}
256*da14cebeSEric Cheng 
257*da14cebeSEric Cheng 	status = dladm_get_conf_field(conf, FVLANID, &u64, sizeof (u64));
258*da14cebeSEric Cheng 	attrp->va_vid = ((status == DLADM_STATUS_OK) ?  (uint16_t)u64 : 0);
259*da14cebeSEric Cheng 
260*da14cebeSEric Cheng 
261*da14cebeSEric Cheng 	status = DLADM_STATUS_OK;
262*da14cebeSEric Cheng done:
263*da14cebeSEric Cheng 	dladm_destroy_conf(conf);
264*da14cebeSEric Cheng 	return (status);
265*da14cebeSEric Cheng }
266*da14cebeSEric Cheng 
267*da14cebeSEric Cheng dladm_status_t
268*da14cebeSEric Cheng dladm_vnic_info(datalink_id_t linkid, dladm_vnic_attr_t *attrp,
269*da14cebeSEric Cheng     uint32_t flags)
270*da14cebeSEric Cheng {
271*da14cebeSEric Cheng 	if (flags == DLADM_OPT_ACTIVE)
272*da14cebeSEric Cheng 		return (i_dladm_vnic_info_active(linkid, attrp));
273*da14cebeSEric Cheng 	else if (flags == DLADM_OPT_PERSIST)
274*da14cebeSEric Cheng 		return (i_dladm_vnic_info_persist(linkid, attrp));
275*da14cebeSEric Cheng 	else
276*da14cebeSEric Cheng 		return (DLADM_STATUS_BADARG);
277*da14cebeSEric Cheng }
278*da14cebeSEric Cheng 
279843e1988Sjohnlev /*
280843e1988Sjohnlev  * Remove a VNIC from the kernel.
281843e1988Sjohnlev  */
282*da14cebeSEric Cheng dladm_status_t
283*da14cebeSEric Cheng i_dladm_vnic_delete_sys(datalink_id_t linkid)
284843e1988Sjohnlev {
285843e1988Sjohnlev 	vnic_ioc_delete_t ioc;
286*da14cebeSEric Cheng 	dladm_status_t status = DLADM_STATUS_OK;
287*da14cebeSEric Cheng 	int rc, fd;
288843e1988Sjohnlev 
289*da14cebeSEric Cheng 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
290843e1988Sjohnlev 		return (dladm_errno2status(errno));
291843e1988Sjohnlev 
292*da14cebeSEric Cheng 	ioc.vd_vnic_id = linkid;
293*da14cebeSEric Cheng 
294*da14cebeSEric Cheng 	rc = ioctl(fd, VNIC_IOC_DELETE, &ioc);
295*da14cebeSEric Cheng 	if (rc < 0)
296*da14cebeSEric Cheng 		status = dladm_errno2status(errno);
297*da14cebeSEric Cheng 
298*da14cebeSEric Cheng 	(void) close(fd);
299*da14cebeSEric Cheng 	return (status);
300843e1988Sjohnlev }
301843e1988Sjohnlev 
302843e1988Sjohnlev /*
303843e1988Sjohnlev  * Convert between MAC address types and their string representations.
304843e1988Sjohnlev  */
305843e1988Sjohnlev 
306843e1988Sjohnlev typedef struct dladm_vnic_addr_type_s {
307*da14cebeSEric Cheng 	const char		*va_str;
308843e1988Sjohnlev 	vnic_mac_addr_type_t	va_type;
309843e1988Sjohnlev } dladm_vnic_addr_type_t;
310843e1988Sjohnlev 
311843e1988Sjohnlev static dladm_vnic_addr_type_t addr_types[] = {
312843e1988Sjohnlev 	{"fixed", VNIC_MAC_ADDR_TYPE_FIXED},
313*da14cebeSEric Cheng 	{"random", VNIC_MAC_ADDR_TYPE_RANDOM},
314*da14cebeSEric Cheng 	{"factory", VNIC_MAC_ADDR_TYPE_FACTORY},
315*da14cebeSEric Cheng 	{"auto", VNIC_MAC_ADDR_TYPE_AUTO},
316*da14cebeSEric Cheng 	{"fixed", VNIC_MAC_ADDR_TYPE_PRIMARY}
317843e1988Sjohnlev };
318843e1988Sjohnlev 
319843e1988Sjohnlev #define	NADDR_TYPES (sizeof (addr_types) / sizeof (dladm_vnic_addr_type_t))
320843e1988Sjohnlev 
321*da14cebeSEric Cheng static const char *
322*da14cebeSEric Cheng dladm_vnic_macaddrtype2str(vnic_mac_addr_type_t type)
323*da14cebeSEric Cheng {
324*da14cebeSEric Cheng 	int i;
325*da14cebeSEric Cheng 
326*da14cebeSEric Cheng 	for (i = 0; i < NADDR_TYPES; i++) {
327*da14cebeSEric Cheng 		if (type == addr_types[i].va_type)
328*da14cebeSEric Cheng 			return (addr_types[i].va_str);
329*da14cebeSEric Cheng 	}
330*da14cebeSEric Cheng 	return (NULL);
331*da14cebeSEric Cheng }
332*da14cebeSEric Cheng 
333d62bc4baSyz147064 dladm_status_t
334d62bc4baSyz147064 dladm_vnic_str2macaddrtype(const char *str, vnic_mac_addr_type_t *val)
335843e1988Sjohnlev {
336843e1988Sjohnlev 	int i;
337843e1988Sjohnlev 	dladm_vnic_addr_type_t *type;
338843e1988Sjohnlev 
339843e1988Sjohnlev 	for (i = 0; i < NADDR_TYPES; i++) {
340843e1988Sjohnlev 		type = &addr_types[i];
341843e1988Sjohnlev 		if (strncmp(str, type->va_str, strlen(type->va_str)) == 0) {
342843e1988Sjohnlev 			*val = type->va_type;
343843e1988Sjohnlev 			return (DLADM_STATUS_OK);
344843e1988Sjohnlev 		}
345843e1988Sjohnlev 	}
346d62bc4baSyz147064 	return (DLADM_STATUS_BADARG);
347843e1988Sjohnlev }
348843e1988Sjohnlev 
349*da14cebeSEric Cheng 
350*da14cebeSEric Cheng 
351843e1988Sjohnlev /*
352*da14cebeSEric Cheng  * Create a new VNIC / VLAN. Update the configuration file and bring it up.
353843e1988Sjohnlev  */
354843e1988Sjohnlev dladm_status_t
355d62bc4baSyz147064 dladm_vnic_create(const char *vnic, datalink_id_t linkid,
356843e1988Sjohnlev     vnic_mac_addr_type_t mac_addr_type, uchar_t *mac_addr, int mac_len,
357*da14cebeSEric Cheng     int *mac_slot, uint_t mac_prefix_len, uint16_t vid,
358*da14cebeSEric Cheng     datalink_id_t *vnic_id_out, dladm_arg_list_t *proplist, uint32_t flags)
359843e1988Sjohnlev {
360*da14cebeSEric Cheng 	dladm_vnic_attr_t attr;
361d62bc4baSyz147064 	datalink_id_t vnic_id;
362d62bc4baSyz147064 	datalink_class_t class;
363*da14cebeSEric Cheng 	uint32_t media = DL_ETHER;
364*da14cebeSEric Cheng 	char name[MAXLINKNAMELEN];
365*da14cebeSEric Cheng 	uchar_t tmp_addr[MAXMACADDRLEN];
366843e1988Sjohnlev 	dladm_status_t status;
367*da14cebeSEric Cheng 	boolean_t is_vlan;
368*da14cebeSEric Cheng 	boolean_t is_etherstub;
369*da14cebeSEric Cheng 	int i;
370843e1988Sjohnlev 
371843e1988Sjohnlev 	/*
372843e1988Sjohnlev 	 * Sanity test arguments.
373843e1988Sjohnlev 	 */
374*da14cebeSEric Cheng 	if ((flags & DLADM_OPT_ACTIVE) == 0)
375*da14cebeSEric Cheng 		return (DLADM_STATUS_NOTSUP);
376*da14cebeSEric Cheng 
377*da14cebeSEric Cheng 	is_vlan = ((flags & DLADM_OPT_VLAN) != 0);
378*da14cebeSEric Cheng 	if (is_vlan && ((vid < 1 || vid > 4094)))
379*da14cebeSEric Cheng 		return (DLADM_STATUS_VIDINVAL);
380*da14cebeSEric Cheng 
381*da14cebeSEric Cheng 	is_etherstub = (linkid == DATALINK_INVALID_LINKID);
382843e1988Sjohnlev 
383843e1988Sjohnlev 	if (mac_len > MAXMACADDRLEN)
384843e1988Sjohnlev 		return (DLADM_STATUS_INVALIDMACADDRLEN);
385843e1988Sjohnlev 
386*da14cebeSEric Cheng 	if (!dladm_vnic_macaddrtype2str(mac_addr_type))
387843e1988Sjohnlev 		return (DLADM_STATUS_INVALIDMACADDRTYPE);
388843e1988Sjohnlev 
389*da14cebeSEric Cheng 	/*
390*da14cebeSEric Cheng 	 * If a random address might be generated, but no prefix
391*da14cebeSEric Cheng 	 * was specified by the caller, use the default MAC address
392*da14cebeSEric Cheng 	 * prefix.
393*da14cebeSEric Cheng 	 */
394*da14cebeSEric Cheng 	if ((mac_addr_type == VNIC_MAC_ADDR_TYPE_RANDOM ||
395*da14cebeSEric Cheng 	    mac_addr_type == VNIC_MAC_ADDR_TYPE_AUTO) &&
396*da14cebeSEric Cheng 	    mac_prefix_len == 0) {
397*da14cebeSEric Cheng 		mac_prefix_len = sizeof (dladm_vnic_def_prefix);
398*da14cebeSEric Cheng 		mac_addr = tmp_addr;
399*da14cebeSEric Cheng 		bcopy(dladm_vnic_def_prefix, mac_addr, mac_prefix_len);
400d62bc4baSyz147064 	}
401d62bc4baSyz147064 
402*da14cebeSEric Cheng 	if ((flags & DLADM_OPT_ANCHOR) == 0) {
403*da14cebeSEric Cheng 		if ((status = dladm_datalink_id2info(linkid, NULL, &class,
404*da14cebeSEric Cheng 		    &media, NULL, 0)) != DLADM_STATUS_OK)
405*da14cebeSEric Cheng 			return (status);
406*da14cebeSEric Cheng 
407*da14cebeSEric Cheng 		if (class == DATALINK_CLASS_VNIC ||
408*da14cebeSEric Cheng 		    class == DATALINK_CLASS_VLAN)
409d62bc4baSyz147064 			return (DLADM_STATUS_BADARG);
410*da14cebeSEric Cheng 	} else {
411*da14cebeSEric Cheng 		/* it's an anchor VNIC */
412*da14cebeSEric Cheng 		if (linkid != DATALINK_INVALID_LINKID || vid != 0)
413*da14cebeSEric Cheng 			return (DLADM_STATUS_BADARG);
414*da14cebeSEric Cheng 	}
415d62bc4baSyz147064 
416d62bc4baSyz147064 	if (vnic == NULL) {
417d62bc4baSyz147064 		flags |= DLADM_OPT_PREFIX;
418*da14cebeSEric Cheng 		(void) strlcpy(name, "vnic", sizeof (name));
419*da14cebeSEric Cheng 	} else {
420*da14cebeSEric Cheng 		(void) strlcpy(name, vnic, sizeof (name));
421d62bc4baSyz147064 	}
422d62bc4baSyz147064 
423*da14cebeSEric Cheng 	class = is_vlan ? DATALINK_CLASS_VLAN :
424*da14cebeSEric Cheng 	    (is_etherstub ? DATALINK_CLASS_ETHERSTUB : DATALINK_CLASS_VNIC);
425*da14cebeSEric Cheng 	if ((status = dladm_create_datalink_id(name, class,
426*da14cebeSEric Cheng 	    media, flags, &vnic_id)) != DLADM_STATUS_OK)
427d62bc4baSyz147064 		return (status);
428*da14cebeSEric Cheng 
429*da14cebeSEric Cheng 	if ((flags & DLADM_OPT_PREFIX) != 0) {
430*da14cebeSEric Cheng 		(void) snprintf(name + 4, sizeof (name), "%llu", vnic_id);
431*da14cebeSEric Cheng 		flags &= ~DLADM_OPT_PREFIX;
432843e1988Sjohnlev 	}
433843e1988Sjohnlev 
434843e1988Sjohnlev 	bzero(&attr, sizeof (attr));
435843e1988Sjohnlev 
436*da14cebeSEric Cheng 	/* Extract resource_ctl and cpu_list from proplist */
437*da14cebeSEric Cheng 	if (proplist != NULL) {
438*da14cebeSEric Cheng 		status = dladm_link_proplist_extract(proplist,
439*da14cebeSEric Cheng 		    &attr.va_resource_props);
440*da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK)
441d62bc4baSyz147064 			goto done;
442d62bc4baSyz147064 	}
443843e1988Sjohnlev 
444*da14cebeSEric Cheng 	attr.va_vnic_id = vnic_id;
445*da14cebeSEric Cheng 	attr.va_link_id = linkid;
446*da14cebeSEric Cheng 	attr.va_mac_addr_type = mac_addr_type;
447*da14cebeSEric Cheng 	attr.va_mac_len = mac_len;
448*da14cebeSEric Cheng 	if (mac_slot != NULL)
449*da14cebeSEric Cheng 		attr.va_mac_slot = *mac_slot;
450*da14cebeSEric Cheng 	if (mac_len > 0)
451*da14cebeSEric Cheng 		bcopy(mac_addr, attr.va_mac_addr, mac_len);
452*da14cebeSEric Cheng 	else if (mac_prefix_len > 0)
453*da14cebeSEric Cheng 		bcopy(mac_addr, attr.va_mac_addr, mac_prefix_len);
454*da14cebeSEric Cheng 	attr.va_mac_prefix_len = mac_prefix_len;
455*da14cebeSEric Cheng 	attr.va_vid = vid;
456*da14cebeSEric Cheng 	attr.va_force = (flags & DLADM_OPT_FORCE) != 0;
457*da14cebeSEric Cheng 	attr.va_hwrings = (flags & DLADM_OPT_HWRINGS) != 0;
458*da14cebeSEric Cheng 
459*da14cebeSEric Cheng 	status = i_dladm_vnic_create_sys(&attr);
460*da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
461*da14cebeSEric Cheng 		goto done;
462*da14cebeSEric Cheng 
463*da14cebeSEric Cheng 	/* Save vnic configuration and its properties */
464*da14cebeSEric Cheng 	if (!(flags & DLADM_OPT_PERSIST))
465*da14cebeSEric Cheng 		goto done;
466*da14cebeSEric Cheng 
467*da14cebeSEric Cheng 	status = dladm_vnic_persist_conf(name, &attr, class);
468*da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK) {
469*da14cebeSEric Cheng 		(void) i_dladm_vnic_delete_sys(vnic_id);
470*da14cebeSEric Cheng 		goto done;
471*da14cebeSEric Cheng 	}
472*da14cebeSEric Cheng 
473*da14cebeSEric Cheng 	if (proplist != NULL) {
474*da14cebeSEric Cheng 		for (i = 0; i < proplist->al_count; i++) {
475*da14cebeSEric Cheng 			dladm_arg_info_t	*aip = &proplist->al_info[i];
476*da14cebeSEric Cheng 
477*da14cebeSEric Cheng 			status = dladm_set_linkprop(vnic_id, aip->ai_name,
478*da14cebeSEric Cheng 			    aip->ai_val, aip->ai_count, DLADM_OPT_PERSIST);
479*da14cebeSEric Cheng 			if (status != DLADM_STATUS_OK)
480*da14cebeSEric Cheng 				break;
481*da14cebeSEric Cheng 		}
482*da14cebeSEric Cheng 
483*da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK) {
484*da14cebeSEric Cheng 			(void) dladm_remove_conf(vnic_id);
485*da14cebeSEric Cheng 			(void) i_dladm_vnic_delete_sys(vnic_id);
486*da14cebeSEric Cheng 		}
487*da14cebeSEric Cheng 	}
488843e1988Sjohnlev 
489d62bc4baSyz147064 done:
490d62bc4baSyz147064 	if (status != DLADM_STATUS_OK) {
491*da14cebeSEric Cheng 		(void) dladm_destroy_datalink_id(vnic_id, flags);
492d62bc4baSyz147064 	} else {
493*da14cebeSEric Cheng 		if (vnic_id_out != NULL)
494d62bc4baSyz147064 			*vnic_id_out = vnic_id;
495*da14cebeSEric Cheng 		if (mac_slot != NULL)
496*da14cebeSEric Cheng 			*mac_slot = attr.va_mac_slot;
497d62bc4baSyz147064 	}
498843e1988Sjohnlev 	return (status);
499843e1988Sjohnlev }
500843e1988Sjohnlev 
501843e1988Sjohnlev /*
502*da14cebeSEric Cheng  * Delete a VNIC / VLAN.
503843e1988Sjohnlev  */
504843e1988Sjohnlev dladm_status_t
505*da14cebeSEric Cheng dladm_vnic_delete(datalink_id_t linkid, uint32_t flags)
506843e1988Sjohnlev {
507d62bc4baSyz147064 	dladm_status_t status;
508*da14cebeSEric Cheng 	datalink_class_t class;
509843e1988Sjohnlev 
510*da14cebeSEric Cheng 	if (flags == 0)
511*da14cebeSEric Cheng 		return (DLADM_STATUS_BADARG);
512843e1988Sjohnlev 
513*da14cebeSEric Cheng 	if ((dladm_datalink_id2info(linkid, NULL, &class, NULL, NULL, 0) !=
514*da14cebeSEric Cheng 	    DLADM_STATUS_OK))
515*da14cebeSEric Cheng 		return (DLADM_STATUS_BADARG);
516d62bc4baSyz147064 
517*da14cebeSEric Cheng 	if ((flags & DLADM_OPT_VLAN) != 0) {
518*da14cebeSEric Cheng 		if (class != DATALINK_CLASS_VLAN)
519*da14cebeSEric Cheng 			return (DLADM_STATUS_BADARG);
520*da14cebeSEric Cheng 	} else {
521*da14cebeSEric Cheng 		if (class != DATALINK_CLASS_VNIC &&
522*da14cebeSEric Cheng 		    class != DATALINK_CLASS_ETHERSTUB)
523*da14cebeSEric Cheng 			return (DLADM_STATUS_BADARG);
524*da14cebeSEric Cheng 	}
525d62bc4baSyz147064 
526*da14cebeSEric Cheng 	if ((flags & DLADM_OPT_ACTIVE) != 0) {
527*da14cebeSEric Cheng 		status = i_dladm_vnic_delete_sys(linkid);
528*da14cebeSEric Cheng 		if (status == DLADM_STATUS_OK) {
529*da14cebeSEric Cheng 			(void) dladm_set_linkprop(linkid, NULL, NULL, 0,
530*da14cebeSEric Cheng 			    DLADM_OPT_ACTIVE);
531*da14cebeSEric Cheng 			(void) dladm_destroy_datalink_id(linkid,
532*da14cebeSEric Cheng 			    DLADM_OPT_ACTIVE);
533*da14cebeSEric Cheng 		} else if (status != DLADM_STATUS_NOTFOUND ||
534*da14cebeSEric Cheng 		    !(flags & DLADM_OPT_PERSIST)) {
535*da14cebeSEric Cheng 			return (status);
536*da14cebeSEric Cheng 		}
537*da14cebeSEric Cheng 	}
538*da14cebeSEric Cheng 	if ((flags & DLADM_OPT_PERSIST) != 0) {
539*da14cebeSEric Cheng 		(void) dladm_destroy_datalink_id(linkid, DLADM_OPT_PERSIST);
540*da14cebeSEric Cheng 		(void) dladm_remove_conf(linkid);
541*da14cebeSEric Cheng 	}
542*da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
543*da14cebeSEric Cheng }
544*da14cebeSEric Cheng 
545*da14cebeSEric Cheng static const char *
546*da14cebeSEric Cheng dladm_vnic_macaddr2str(const uchar_t *mac, char *buf)
547*da14cebeSEric Cheng {
548*da14cebeSEric Cheng 	static char unknown_mac[] = {0, 0, 0, 0, 0, 0};
549*da14cebeSEric Cheng 
550*da14cebeSEric Cheng 	if (buf == NULL)
551*da14cebeSEric Cheng 		return (NULL);
552*da14cebeSEric Cheng 
553*da14cebeSEric Cheng 	if (bcmp(unknown_mac, mac, ETHERADDRL) == 0)
554*da14cebeSEric Cheng 		(void) strlcpy(buf, "unknown", DLADM_STRSIZE);
555*da14cebeSEric Cheng 	else
556*da14cebeSEric Cheng 		return (_link_ntoa(mac, buf, ETHERADDRL, IFT_OTHER));
557*da14cebeSEric Cheng 
558*da14cebeSEric Cheng 	return (buf);
559*da14cebeSEric Cheng }
560*da14cebeSEric Cheng 
561*da14cebeSEric Cheng static dladm_status_t
562*da14cebeSEric Cheng dladm_vnic_str2macaddr(const char *str, uchar_t *buf)
563*da14cebeSEric Cheng {
564*da14cebeSEric Cheng 	int len = 0;
565*da14cebeSEric Cheng 	uchar_t *b = _link_aton(str, &len);
566*da14cebeSEric Cheng 
567*da14cebeSEric Cheng 	if (b == NULL || len >= MAXMACADDRLEN)
568*da14cebeSEric Cheng 		return (DLADM_STATUS_BADARG);
569*da14cebeSEric Cheng 
570*da14cebeSEric Cheng 	bcopy(b, buf, len);
571*da14cebeSEric Cheng 	free(b);
572*da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
573*da14cebeSEric Cheng }
574*da14cebeSEric Cheng 
575*da14cebeSEric Cheng 
576*da14cebeSEric Cheng static dladm_status_t
577*da14cebeSEric Cheng dladm_vnic_persist_conf(const char *name, dladm_vnic_attr_t *attrp,
578*da14cebeSEric Cheng     datalink_class_t class)
579*da14cebeSEric Cheng {
580*da14cebeSEric Cheng 	dladm_conf_t conf = DLADM_INVALID_CONF;
581*da14cebeSEric Cheng 	dladm_status_t status;
582*da14cebeSEric Cheng 	char macstr[ETHERADDRL * 3];
583*da14cebeSEric Cheng 	uint64_t u64;
584*da14cebeSEric Cheng 
585*da14cebeSEric Cheng 	if ((status = dladm_create_conf(name, attrp->va_vnic_id,
586*da14cebeSEric Cheng 	    class, DL_ETHER, &conf)) != DLADM_STATUS_OK)
587*da14cebeSEric Cheng 		return (status);
588*da14cebeSEric Cheng 
589*da14cebeSEric Cheng 	if (attrp->va_link_id != DATALINK_INVALID_LINKID) {
590*da14cebeSEric Cheng 		u64 = attrp->va_link_id;
591*da14cebeSEric Cheng 		status = dladm_set_conf_field(conf, FLINKOVER,
592*da14cebeSEric Cheng 		    DLADM_TYPE_UINT64, &u64);
593d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
594*da14cebeSEric Cheng 			goto done;
595*da14cebeSEric Cheng 	}
596d62bc4baSyz147064 
597*da14cebeSEric Cheng 	if (class != DATALINK_CLASS_VLAN) {
598*da14cebeSEric Cheng 		u64 = attrp->va_mac_addr_type;
599*da14cebeSEric Cheng 		status = dladm_set_conf_field(conf, FMADDRTYPE,
600*da14cebeSEric Cheng 		    DLADM_TYPE_UINT64, &u64);
601*da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK)
602*da14cebeSEric Cheng 			goto done;
603*da14cebeSEric Cheng 
604*da14cebeSEric Cheng 		if (attrp->va_mac_len != ETHERADDRL) {
605*da14cebeSEric Cheng 			u64 = attrp->va_mac_len;
606*da14cebeSEric Cheng 			status = dladm_set_conf_field(conf, FMADDRLEN,
607*da14cebeSEric Cheng 			    DLADM_TYPE_UINT64, &u64);
608*da14cebeSEric Cheng 			if (status != DLADM_STATUS_OK)
609*da14cebeSEric Cheng 				goto done;
610*da14cebeSEric Cheng 		}
611*da14cebeSEric Cheng 	}
612*da14cebeSEric Cheng 
613*da14cebeSEric Cheng 	if (attrp->va_hwrings) {
614*da14cebeSEric Cheng 		boolean_t hwrings = attrp->va_hwrings;
615*da14cebeSEric Cheng 		status = dladm_set_conf_field(conf, FHWRINGS,
616*da14cebeSEric Cheng 		    DLADM_TYPE_BOOLEAN, &hwrings);
617*da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK)
618*da14cebeSEric Cheng 			goto done;
619*da14cebeSEric Cheng 	}
620*da14cebeSEric Cheng 
621*da14cebeSEric Cheng 	if (class != DATALINK_CLASS_VLAN) {
622*da14cebeSEric Cheng 		if (attrp->va_mac_slot != -1) {
623*da14cebeSEric Cheng 			u64 = attrp->va_mac_slot;
624*da14cebeSEric Cheng 			status = dladm_set_conf_field(conf, FMADDRSLOT,
625*da14cebeSEric Cheng 			    DLADM_TYPE_UINT64, &u64);
626*da14cebeSEric Cheng 			if (status != DLADM_STATUS_OK)
627*da14cebeSEric Cheng 			goto done;
628*da14cebeSEric Cheng 		}
629*da14cebeSEric Cheng 
630*da14cebeSEric Cheng 		if (attrp->va_mac_prefix_len !=
631*da14cebeSEric Cheng 		    sizeof (dladm_vnic_def_prefix)) {
632*da14cebeSEric Cheng 			u64 = attrp->va_mac_prefix_len;
633*da14cebeSEric Cheng 			status = dladm_set_conf_field(conf, FMADDRPREFIXLEN,
634*da14cebeSEric Cheng 			    DLADM_TYPE_UINT64, &u64);
635*da14cebeSEric Cheng 			if (status != DLADM_STATUS_OK)
636*da14cebeSEric Cheng 				goto done;
637*da14cebeSEric Cheng 		}
638*da14cebeSEric Cheng 
639*da14cebeSEric Cheng 		(void) dladm_vnic_macaddr2str(attrp->va_mac_addr, macstr);
640*da14cebeSEric Cheng 		status = dladm_set_conf_field(conf, FMACADDR, DLADM_TYPE_STR,
641*da14cebeSEric Cheng 		    macstr);
642*da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK)
643*da14cebeSEric Cheng 			goto done;
644*da14cebeSEric Cheng 	}
645*da14cebeSEric Cheng 
646*da14cebeSEric Cheng 	if (attrp->va_vid != 0) {
647*da14cebeSEric Cheng 		u64 = attrp->va_vid;
648*da14cebeSEric Cheng 		status = dladm_set_conf_field(conf, FVLANID,
649*da14cebeSEric Cheng 		    DLADM_TYPE_UINT64, &u64);
650*da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK)
651*da14cebeSEric Cheng 			goto done;
652*da14cebeSEric Cheng 	}
653*da14cebeSEric Cheng 
654*da14cebeSEric Cheng 	/*
655*da14cebeSEric Cheng 	 * Commit the link configuration.
656*da14cebeSEric Cheng 	 */
657*da14cebeSEric Cheng 	status = dladm_write_conf(conf);
658*da14cebeSEric Cheng 
659*da14cebeSEric Cheng done:
660*da14cebeSEric Cheng 	dladm_destroy_conf(conf);
661d62bc4baSyz147064 	return (status);
662843e1988Sjohnlev }
663*da14cebeSEric Cheng 
664*da14cebeSEric Cheng typedef struct dladm_vnic_up_arg_s {
665*da14cebeSEric Cheng 	uint32_t	flags;
666*da14cebeSEric Cheng 	dladm_status_t	status;
667*da14cebeSEric Cheng } dladm_vnic_up_arg_t;
668*da14cebeSEric Cheng 
669*da14cebeSEric Cheng #define	DLADM_VNIC_UP_FIRST_WALK	0x1
670*da14cebeSEric Cheng #define	DLADM_VNIC_UP_SECOND_WALK	0x2
671*da14cebeSEric Cheng 
672*da14cebeSEric Cheng static int
673*da14cebeSEric Cheng i_dladm_vnic_up(datalink_id_t linkid, void *arg)
674*da14cebeSEric Cheng {
675*da14cebeSEric Cheng 	dladm_status_t *statusp = &(((dladm_vnic_up_arg_t *)arg)->status);
676*da14cebeSEric Cheng 	dladm_vnic_attr_t attr;
677*da14cebeSEric Cheng 	dladm_status_t status;
678*da14cebeSEric Cheng 	dladm_arg_list_t *proplist;
679*da14cebeSEric Cheng 	uint32_t flags = ((dladm_vnic_up_arg_t *)arg)->flags;
680*da14cebeSEric Cheng 
681*da14cebeSEric Cheng 	bzero(&attr, sizeof (attr));
682*da14cebeSEric Cheng 
683*da14cebeSEric Cheng 	status = dladm_vnic_info(linkid, &attr, DLADM_OPT_PERSIST);
684*da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
685*da14cebeSEric Cheng 		goto done;
686*da14cebeSEric Cheng 
687*da14cebeSEric Cheng 	/*
688*da14cebeSEric Cheng 	 * Create the vnics that request hardware group first
689*da14cebeSEric Cheng 	 * Create the vnics that don't request hardware group in the second walk
690*da14cebeSEric Cheng 	 */
691*da14cebeSEric Cheng 	if ((flags == DLADM_VNIC_UP_FIRST_WALK && !attr.va_hwrings) ||
692*da14cebeSEric Cheng 	    (flags == DLADM_VNIC_UP_SECOND_WALK && attr.va_hwrings))
693*da14cebeSEric Cheng 			goto done;
694*da14cebeSEric Cheng 
695*da14cebeSEric Cheng 	/* Get all properties for this vnic */
696*da14cebeSEric Cheng 	status = dladm_link_get_proplist(linkid, &proplist);
697*da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
698*da14cebeSEric Cheng 		goto done;
699*da14cebeSEric Cheng 
700*da14cebeSEric Cheng 	if (proplist != NULL) {
701*da14cebeSEric Cheng 		status = dladm_link_proplist_extract(proplist,
702*da14cebeSEric Cheng 		    &attr.va_resource_props);
703*da14cebeSEric Cheng 	}
704*da14cebeSEric Cheng 
705*da14cebeSEric Cheng 	status = i_dladm_vnic_create_sys(&attr);
706*da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
707*da14cebeSEric Cheng 		goto done;
708*da14cebeSEric Cheng 
709*da14cebeSEric Cheng 	if ((status = dladm_up_datalink_id(linkid)) != DLADM_STATUS_OK) {
710*da14cebeSEric Cheng 		(void) i_dladm_vnic_delete_sys(linkid);
711*da14cebeSEric Cheng 		goto done;
712*da14cebeSEric Cheng 	}
713*da14cebeSEric Cheng done:
714*da14cebeSEric Cheng 	*statusp = status;
715*da14cebeSEric Cheng 	return (DLADM_WALK_CONTINUE);
716*da14cebeSEric Cheng }
717*da14cebeSEric Cheng 
718*da14cebeSEric Cheng dladm_status_t
719*da14cebeSEric Cheng dladm_vnic_up(datalink_id_t linkid, uint32_t flags)
720*da14cebeSEric Cheng {
721*da14cebeSEric Cheng 	dladm_vnic_up_arg_t vnic_arg;
722*da14cebeSEric Cheng 	datalink_class_t class;
723*da14cebeSEric Cheng 
724*da14cebeSEric Cheng 	class = ((flags & DLADM_OPT_VLAN) != 0) ? DATALINK_CLASS_VLAN :
725*da14cebeSEric Cheng 	    (DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB);
726*da14cebeSEric Cheng 
727*da14cebeSEric Cheng 	if (linkid == DATALINK_ALL_LINKID) {
728*da14cebeSEric Cheng 		vnic_arg.flags = DLADM_VNIC_UP_FIRST_WALK;
729*da14cebeSEric Cheng 		(void) dladm_walk_datalink_id(i_dladm_vnic_up, &vnic_arg,
730*da14cebeSEric Cheng 		    class, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
731*da14cebeSEric Cheng 		vnic_arg.flags = DLADM_VNIC_UP_SECOND_WALK;
732*da14cebeSEric Cheng 		(void) dladm_walk_datalink_id(i_dladm_vnic_up, &vnic_arg,
733*da14cebeSEric Cheng 		    class, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
734*da14cebeSEric Cheng 		return (DLADM_STATUS_OK);
735*da14cebeSEric Cheng 	} else {
736*da14cebeSEric Cheng 		(void) i_dladm_vnic_up(linkid, &vnic_arg);
737*da14cebeSEric Cheng 		return (vnic_arg.status);
738*da14cebeSEric Cheng 	}
739*da14cebeSEric Cheng }
740