xref: /illumos-gate/usr/src/lib/libdladm/common/libdlvnic.c (revision 6e375c8351497b82ffa4f33cbf61d712999b4605)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <stdio.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <string.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <stropts.h>
33 #include <stdlib.h>
34 #include <errno.h>
35 #include <strings.h>
36 #include <libintl.h>
37 #include <net/if_types.h>
38 #include <net/if_dl.h>
39 #include <sys/dld.h>
40 #include <libdladm_impl.h>
41 #include <libdllink.h>
42 #include <libdlvnic.h>
43 
44 /*
45  * VNIC administration library.
46  */
47 
48 /*
49  * Default random MAC address prefix (locally administered).
50  */
51 static char dladm_vnic_def_prefix[] = {0x02, 0x08, 0x20};
52 
53 static dladm_status_t	dladm_vnic_persist_conf(dladm_handle_t,
54 			    const char *name, dladm_vnic_attr_t *,
55 			    datalink_class_t);
56 static const char	*dladm_vnic_macaddr2str(const uchar_t *, char *);
57 static dladm_status_t	dladm_vnic_str2macaddr(const char *, uchar_t *);
58 
59 /*
60  * Convert a diagnostic returned by the kernel into a dladm_status_t.
61  */
62 static dladm_status_t
63 dladm_vnic_diag2status(vnic_ioc_diag_t ioc_diag)
64 {
65 	switch (ioc_diag) {
66 	case VNIC_IOC_DIAG_MACADDR_INVALID:
67 		return (DLADM_STATUS_INVALIDMACADDR);
68 	case VNIC_IOC_DIAG_MACADDRLEN_INVALID:
69 		return (DLADM_STATUS_INVALIDMACADDRLEN);
70 	case VNIC_IOC_DIAG_MACADDR_NIC:
71 		return (DLADM_STATUS_INVALIDMACADDRNIC);
72 	case VNIC_IOC_DIAG_MACADDR_INUSE:
73 		return (DLADM_STATUS_INVALIDMACADDRINUSE);
74 	case VNIC_IOC_DIAG_MACFACTORYSLOTINVALID:
75 		return (DLADM_STATUS_MACFACTORYSLOTINVALID);
76 	case VNIC_IOC_DIAG_MACFACTORYSLOTUSED:
77 		return (DLADM_STATUS_MACFACTORYSLOTUSED);
78 	case VNIC_IOC_DIAG_MACFACTORYSLOTALLUSED:
79 		return (DLADM_STATUS_MACFACTORYSLOTALLUSED);
80 	case VNIC_IOC_DIAG_MACFACTORYNOTSUP:
81 		return (DLADM_STATUS_MACFACTORYNOTSUP);
82 	case VNIC_IOC_DIAG_MACPREFIX_INVALID:
83 		return (DLADM_STATUS_INVALIDMACPREFIX);
84 	case VNIC_IOC_DIAG_MACPREFIXLEN_INVALID:
85 		return (DLADM_STATUS_INVALIDMACPREFIXLEN);
86 	case VNIC_IOC_DIAG_MACMARGIN_INVALID:
87 		return (DLADM_STATUS_INVALID_MACMARGIN);
88 	case VNIC_IOC_DIAG_NO_HWRINGS:
89 		return (DLADM_STATUS_NO_HWRINGS);
90 	}
91 	return (DLADM_STATUS_OK);
92 }
93 
94 /*
95  * Send a create command to the VNIC driver.
96  */
97 dladm_status_t
98 i_dladm_vnic_create_sys(dladm_handle_t handle, dladm_vnic_attr_t *attr)
99 {
100 	int rc;
101 	vnic_ioc_create_t ioc;
102 	dladm_status_t status = DLADM_STATUS_OK;
103 
104 	bzero(&ioc, sizeof (ioc));
105 	ioc.vc_vnic_id = attr->va_vnic_id;
106 	ioc.vc_link_id = attr->va_link_id;
107 	ioc.vc_mac_addr_type = attr->va_mac_addr_type;
108 	ioc.vc_mac_len = attr->va_mac_len;
109 	ioc.vc_mac_slot = attr->va_mac_slot;
110 	ioc.vc_mac_prefix_len = attr->va_mac_prefix_len;
111 	ioc.vc_vid = attr->va_vid;
112 	ioc.vc_flags = attr->va_force ? VNIC_IOC_CREATE_FORCE : 0;
113 	ioc.vc_flags |= attr->va_hwrings ? VNIC_IOC_CREATE_REQ_HWRINGS : 0;
114 
115 	if (attr->va_mac_len > 0 || ioc.vc_mac_prefix_len > 0)
116 		bcopy(attr->va_mac_addr, ioc.vc_mac_addr, MAXMACADDRLEN);
117 	bcopy(&attr->va_resource_props, &ioc.vc_resource_props,
118 	    sizeof (mac_resource_props_t));
119 	if (attr->va_link_id == DATALINK_INVALID_LINKID)
120 		ioc.vc_flags |= VNIC_IOC_CREATE_ANCHOR;
121 
122 	rc = ioctl(dladm_dld_fd(handle), VNIC_IOC_CREATE, &ioc);
123 	if (rc < 0)
124 		status = dladm_errno2status(errno);
125 
126 	if (status != DLADM_STATUS_OK) {
127 		if (ioc.vc_diag != VNIC_IOC_DIAG_NONE)
128 			status = dladm_vnic_diag2status(ioc.vc_diag);
129 	}
130 	if (status != DLADM_STATUS_OK)
131 		return (status);
132 
133 	attr->va_mac_addr_type = ioc.vc_mac_addr_type;
134 	switch (ioc.vc_mac_addr_type) {
135 	case VNIC_MAC_ADDR_TYPE_FACTORY:
136 		attr->va_mac_slot = ioc.vc_mac_slot;
137 		break;
138 	case VNIC_MAC_ADDR_TYPE_RANDOM:
139 		bcopy(ioc.vc_mac_addr, attr->va_mac_addr, MAXMACADDRLEN);
140 		attr->va_mac_len = ioc.vc_mac_len;
141 		break;
142 	}
143 	return (status);
144 }
145 
146 /*
147  * Get the configuration information of the given VNIC.
148  */
149 static dladm_status_t
150 i_dladm_vnic_info_active(dladm_handle_t handle, datalink_id_t linkid,
151     dladm_vnic_attr_t *attrp)
152 {
153 	vnic_ioc_info_t ioc;
154 	vnic_info_t *vnic;
155 	int rc;
156 	dladm_status_t status = DLADM_STATUS_OK;
157 
158 	bzero(&ioc, sizeof (ioc));
159 	vnic = &ioc.vi_info;
160 	vnic->vn_vnic_id = linkid;
161 
162 	rc = ioctl(dladm_dld_fd(handle), VNIC_IOC_INFO, &ioc);
163 	if (rc != 0) {
164 		status = dladm_errno2status(errno);
165 		goto bail;
166 	}
167 
168 	attrp->va_vnic_id = vnic->vn_vnic_id;
169 	attrp->va_link_id = vnic->vn_link_id;
170 	attrp->va_mac_addr_type = vnic->vn_mac_addr_type;
171 	bcopy(vnic->vn_mac_addr, attrp->va_mac_addr, MAXMACADDRLEN);
172 	attrp->va_mac_len = vnic->vn_mac_len;
173 	attrp->va_mac_slot = vnic->vn_mac_slot;
174 	attrp->va_mac_prefix_len = vnic->vn_mac_prefix_len;
175 	attrp->va_vid = vnic->vn_vid;
176 	attrp->va_force = vnic->vn_force;
177 
178 bail:
179 	return (status);
180 }
181 
182 static dladm_status_t
183 i_dladm_vnic_info_persist(dladm_handle_t handle, datalink_id_t linkid,
184     dladm_vnic_attr_t *attrp)
185 {
186 	dladm_conf_t conf;
187 	dladm_status_t status;
188 	char macstr[ETHERADDRL * 3];
189 	uint64_t u64;
190 	datalink_class_t class;
191 
192 	attrp->va_vnic_id = linkid;
193 	if ((status = dladm_read_conf(handle, linkid, &conf)) !=
194 	    DLADM_STATUS_OK)
195 		return (status);
196 
197 	status = dladm_get_conf_field(handle, conf, FLINKOVER, &u64,
198 	    sizeof (u64));
199 	attrp->va_link_id = ((status == DLADM_STATUS_OK) ?
200 	    (datalink_id_t)u64 : DATALINK_INVALID_LINKID);
201 
202 	status = dladm_get_conf_field(handle, conf, FHWRINGS,
203 	    &attrp->va_hwrings, sizeof (boolean_t));
204 
205 	if (status != DLADM_STATUS_OK && status != DLADM_STATUS_NOTFOUND)
206 		goto done;
207 	if (status == DLADM_STATUS_NOTFOUND)
208 		attrp->va_hwrings = B_FALSE;
209 
210 	if ((status = dladm_datalink_id2info(handle, linkid, NULL, &class,
211 	    NULL, NULL, 0)) != DLADM_STATUS_OK)
212 		goto done;
213 
214 	if (class == DATALINK_CLASS_VLAN) {
215 		if (attrp->va_link_id == DATALINK_INVALID_LINKID) {
216 			status = DLADM_STATUS_BADARG;
217 			goto done;
218 		}
219 		attrp->va_mac_addr_type = VNIC_MAC_ADDR_TYPE_PRIMARY;
220 		attrp->va_mac_len = 0;
221 	} else {
222 		status = dladm_get_conf_field(handle, conf, FMADDRTYPE, &u64,
223 		    sizeof (u64));
224 		if (status != DLADM_STATUS_OK)
225 			goto done;
226 
227 		attrp->va_mac_addr_type = (vnic_mac_addr_type_t)u64;
228 
229 		status = dladm_get_conf_field(handle, conf, FMADDRLEN, &u64,
230 		    sizeof (u64));
231 		attrp->va_mac_len = ((status == DLADM_STATUS_OK) ?
232 		    (uint_t)u64 : ETHERADDRL);
233 
234 		status = dladm_get_conf_field(handle, conf, FMADDRSLOT, &u64,
235 		    sizeof (u64));
236 		attrp->va_mac_slot = ((status == DLADM_STATUS_OK) ?
237 		    (int)u64 : -1);
238 
239 		status = dladm_get_conf_field(handle, conf, FMADDRPREFIXLEN,
240 		    &u64, sizeof (u64));
241 		attrp->va_mac_prefix_len = ((status == DLADM_STATUS_OK) ?
242 		    (uint_t)u64 : sizeof (dladm_vnic_def_prefix));
243 
244 		status = dladm_get_conf_field(handle, conf, FMACADDR, macstr,
245 		    sizeof (macstr));
246 		if (status != DLADM_STATUS_OK)
247 			goto done;
248 
249 		status = dladm_vnic_str2macaddr(macstr, attrp->va_mac_addr);
250 		if (status != DLADM_STATUS_OK)
251 			goto done;
252 	}
253 
254 	status = dladm_get_conf_field(handle, conf, FVLANID, &u64,
255 	    sizeof (u64));
256 	attrp->va_vid = ((status == DLADM_STATUS_OK) ?  (uint16_t)u64 : 0);
257 
258 
259 	status = DLADM_STATUS_OK;
260 done:
261 	dladm_destroy_conf(handle, conf);
262 	return (status);
263 }
264 
265 dladm_status_t
266 dladm_vnic_info(dladm_handle_t handle, datalink_id_t linkid,
267     dladm_vnic_attr_t *attrp, uint32_t flags)
268 {
269 	if (flags == DLADM_OPT_ACTIVE)
270 		return (i_dladm_vnic_info_active(handle, linkid, attrp));
271 	else if (flags == DLADM_OPT_PERSIST)
272 		return (i_dladm_vnic_info_persist(handle, linkid, attrp));
273 	else
274 		return (DLADM_STATUS_BADARG);
275 }
276 
277 /*
278  * Remove a VNIC from the kernel.
279  */
280 dladm_status_t
281 i_dladm_vnic_delete_sys(dladm_handle_t handle, datalink_id_t linkid)
282 {
283 	vnic_ioc_delete_t ioc;
284 	dladm_status_t status = DLADM_STATUS_OK;
285 	int rc;
286 
287 	ioc.vd_vnic_id = linkid;
288 
289 	rc = ioctl(dladm_dld_fd(handle), VNIC_IOC_DELETE, &ioc);
290 	if (rc < 0)
291 		status = dladm_errno2status(errno);
292 
293 	return (status);
294 }
295 
296 /*
297  * Convert between MAC address types and their string representations.
298  */
299 
300 typedef struct dladm_vnic_addr_type_s {
301 	const char		*va_str;
302 	vnic_mac_addr_type_t	va_type;
303 } dladm_vnic_addr_type_t;
304 
305 static dladm_vnic_addr_type_t addr_types[] = {
306 	{"fixed", VNIC_MAC_ADDR_TYPE_FIXED},
307 	{"random", VNIC_MAC_ADDR_TYPE_RANDOM},
308 	{"factory", VNIC_MAC_ADDR_TYPE_FACTORY},
309 	{"auto", VNIC_MAC_ADDR_TYPE_AUTO},
310 	{"fixed", VNIC_MAC_ADDR_TYPE_PRIMARY}
311 };
312 
313 #define	NADDR_TYPES (sizeof (addr_types) / sizeof (dladm_vnic_addr_type_t))
314 
315 static const char *
316 dladm_vnic_macaddrtype2str(vnic_mac_addr_type_t type)
317 {
318 	int i;
319 
320 	for (i = 0; i < NADDR_TYPES; i++) {
321 		if (type == addr_types[i].va_type)
322 			return (addr_types[i].va_str);
323 	}
324 	return (NULL);
325 }
326 
327 dladm_status_t
328 dladm_vnic_str2macaddrtype(const char *str, vnic_mac_addr_type_t *val)
329 {
330 	int i;
331 	dladm_vnic_addr_type_t *type;
332 
333 	for (i = 0; i < NADDR_TYPES; i++) {
334 		type = &addr_types[i];
335 		if (strncmp(str, type->va_str, strlen(type->va_str)) == 0) {
336 			*val = type->va_type;
337 			return (DLADM_STATUS_OK);
338 		}
339 	}
340 	return (DLADM_STATUS_BADARG);
341 }
342 
343 
344 
345 /*
346  * Create a new VNIC / VLAN. Update the configuration file and bring it up.
347  */
348 dladm_status_t
349 dladm_vnic_create(dladm_handle_t handle, const char *vnic, datalink_id_t linkid,
350     vnic_mac_addr_type_t mac_addr_type, uchar_t *mac_addr, int mac_len,
351     int *mac_slot, uint_t mac_prefix_len, uint16_t vid,
352     datalink_id_t *vnic_id_out, dladm_arg_list_t *proplist, uint32_t flags)
353 {
354 	dladm_vnic_attr_t attr;
355 	datalink_id_t vnic_id;
356 	datalink_class_t class;
357 	uint32_t media = DL_ETHER;
358 	char name[MAXLINKNAMELEN];
359 	uchar_t tmp_addr[MAXMACADDRLEN];
360 	dladm_status_t status;
361 	boolean_t is_vlan;
362 	boolean_t is_etherstub;
363 	int i;
364 
365 	/*
366 	 * Sanity test arguments.
367 	 */
368 	if ((flags & DLADM_OPT_ACTIVE) == 0)
369 		return (DLADM_STATUS_NOTSUP);
370 
371 	is_vlan = ((flags & DLADM_OPT_VLAN) != 0);
372 	if (is_vlan && ((vid < 1 || vid > 4094)))
373 		return (DLADM_STATUS_VIDINVAL);
374 
375 	is_etherstub = (linkid == DATALINK_INVALID_LINKID);
376 
377 	if (mac_len > MAXMACADDRLEN)
378 		return (DLADM_STATUS_INVALIDMACADDRLEN);
379 
380 	if (!dladm_vnic_macaddrtype2str(mac_addr_type))
381 		return (DLADM_STATUS_INVALIDMACADDRTYPE);
382 
383 	/*
384 	 * If a random address might be generated, but no prefix
385 	 * was specified by the caller, use the default MAC address
386 	 * prefix.
387 	 */
388 	if ((mac_addr_type == VNIC_MAC_ADDR_TYPE_RANDOM ||
389 	    mac_addr_type == VNIC_MAC_ADDR_TYPE_AUTO) &&
390 	    mac_prefix_len == 0) {
391 		mac_prefix_len = sizeof (dladm_vnic_def_prefix);
392 		mac_addr = tmp_addr;
393 		bcopy(dladm_vnic_def_prefix, mac_addr, mac_prefix_len);
394 	}
395 
396 	if ((flags & DLADM_OPT_ANCHOR) == 0) {
397 		if ((status = dladm_datalink_id2info(handle, linkid, NULL,
398 		    &class, &media, NULL, 0)) != DLADM_STATUS_OK)
399 			return (status);
400 
401 		if (class == DATALINK_CLASS_VNIC ||
402 		    class == DATALINK_CLASS_VLAN)
403 			return (DLADM_STATUS_BADARG);
404 	} else {
405 		/* it's an anchor VNIC */
406 		if (linkid != DATALINK_INVALID_LINKID || vid != 0)
407 			return (DLADM_STATUS_BADARG);
408 	}
409 
410 	if (vnic == NULL) {
411 		flags |= DLADM_OPT_PREFIX;
412 		(void) strlcpy(name, "vnic", sizeof (name));
413 	} else {
414 		(void) strlcpy(name, vnic, sizeof (name));
415 	}
416 
417 	class = is_vlan ? DATALINK_CLASS_VLAN :
418 	    (is_etherstub ? DATALINK_CLASS_ETHERSTUB : DATALINK_CLASS_VNIC);
419 	if ((status = dladm_create_datalink_id(handle, name, class,
420 	    media, flags, &vnic_id)) != DLADM_STATUS_OK)
421 		return (status);
422 
423 	if ((flags & DLADM_OPT_PREFIX) != 0) {
424 		(void) snprintf(name + 4, sizeof (name), "%llu", vnic_id);
425 		flags &= ~DLADM_OPT_PREFIX;
426 	}
427 
428 	bzero(&attr, sizeof (attr));
429 
430 	/* Extract resource_ctl and cpu_list from proplist */
431 	if (proplist != NULL) {
432 		status = dladm_link_proplist_extract(handle, proplist,
433 		    &attr.va_resource_props);
434 		if (status != DLADM_STATUS_OK)
435 			goto done;
436 	}
437 
438 	attr.va_vnic_id = vnic_id;
439 	attr.va_link_id = linkid;
440 	attr.va_mac_addr_type = mac_addr_type;
441 	attr.va_mac_len = mac_len;
442 	if (mac_slot != NULL)
443 		attr.va_mac_slot = *mac_slot;
444 	if (mac_len > 0)
445 		bcopy(mac_addr, attr.va_mac_addr, mac_len);
446 	else if (mac_prefix_len > 0)
447 		bcopy(mac_addr, attr.va_mac_addr, mac_prefix_len);
448 	attr.va_mac_prefix_len = mac_prefix_len;
449 	attr.va_vid = vid;
450 	attr.va_force = (flags & DLADM_OPT_FORCE) != 0;
451 	attr.va_hwrings = (flags & DLADM_OPT_HWRINGS) != 0;
452 
453 	status = i_dladm_vnic_create_sys(handle, &attr);
454 	if (status != DLADM_STATUS_OK)
455 		goto done;
456 
457 	/* Save vnic configuration and its properties */
458 	if (!(flags & DLADM_OPT_PERSIST))
459 		goto done;
460 
461 	status = dladm_vnic_persist_conf(handle, name, &attr, class);
462 	if (status != DLADM_STATUS_OK) {
463 		(void) i_dladm_vnic_delete_sys(handle, vnic_id);
464 		goto done;
465 	}
466 
467 	if (proplist != NULL) {
468 		for (i = 0; i < proplist->al_count; i++) {
469 			dladm_arg_info_t	*aip = &proplist->al_info[i];
470 
471 			status = dladm_set_linkprop(handle, vnic_id,
472 			    aip->ai_name, aip->ai_val, aip->ai_count,
473 			    DLADM_OPT_PERSIST);
474 			if (status != DLADM_STATUS_OK)
475 				break;
476 		}
477 
478 		if (status != DLADM_STATUS_OK) {
479 			(void) dladm_remove_conf(handle, vnic_id);
480 			(void) i_dladm_vnic_delete_sys(handle, vnic_id);
481 		}
482 	}
483 
484 done:
485 	if (status != DLADM_STATUS_OK) {
486 		(void) dladm_destroy_datalink_id(handle, vnic_id, flags);
487 	} else {
488 		if (vnic_id_out != NULL)
489 			*vnic_id_out = vnic_id;
490 		if (mac_slot != NULL)
491 			*mac_slot = attr.va_mac_slot;
492 	}
493 	return (status);
494 }
495 
496 /*
497  * Delete a VNIC / VLAN.
498  */
499 dladm_status_t
500 dladm_vnic_delete(dladm_handle_t handle, datalink_id_t linkid, uint32_t flags)
501 {
502 	dladm_status_t status;
503 	datalink_class_t class;
504 
505 	if (flags == 0)
506 		return (DLADM_STATUS_BADARG);
507 
508 	if ((dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, NULL, 0)
509 	    != DLADM_STATUS_OK))
510 		return (DLADM_STATUS_BADARG);
511 
512 	if ((flags & DLADM_OPT_VLAN) != 0) {
513 		if (class != DATALINK_CLASS_VLAN)
514 			return (DLADM_STATUS_BADARG);
515 	} else {
516 		if (class != DATALINK_CLASS_VNIC &&
517 		    class != DATALINK_CLASS_ETHERSTUB)
518 			return (DLADM_STATUS_BADARG);
519 	}
520 
521 	if ((flags & DLADM_OPT_ACTIVE) != 0) {
522 		status = i_dladm_vnic_delete_sys(handle, linkid);
523 		if (status == DLADM_STATUS_OK) {
524 			(void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0,
525 			    DLADM_OPT_ACTIVE);
526 			(void) dladm_destroy_datalink_id(handle, linkid,
527 			    DLADM_OPT_ACTIVE);
528 		} else if (status != DLADM_STATUS_NOTFOUND ||
529 		    !(flags & DLADM_OPT_PERSIST)) {
530 			return (status);
531 		}
532 	}
533 	if ((flags & DLADM_OPT_PERSIST) != 0) {
534 		(void) dladm_destroy_datalink_id(handle, linkid,
535 		    DLADM_OPT_PERSIST);
536 		(void) dladm_remove_conf(handle, linkid);
537 	}
538 	return (DLADM_STATUS_OK);
539 }
540 
541 static const char *
542 dladm_vnic_macaddr2str(const uchar_t *mac, char *buf)
543 {
544 	static char unknown_mac[] = {0, 0, 0, 0, 0, 0};
545 
546 	if (buf == NULL)
547 		return (NULL);
548 
549 	if (bcmp(unknown_mac, mac, ETHERADDRL) == 0)
550 		(void) strlcpy(buf, "unknown", DLADM_STRSIZE);
551 	else
552 		return (_link_ntoa(mac, buf, ETHERADDRL, IFT_OTHER));
553 
554 	return (buf);
555 }
556 
557 static dladm_status_t
558 dladm_vnic_str2macaddr(const char *str, uchar_t *buf)
559 {
560 	int len = 0;
561 	uchar_t *b = _link_aton(str, &len);
562 
563 	if (b == NULL || len >= MAXMACADDRLEN)
564 		return (DLADM_STATUS_BADARG);
565 
566 	bcopy(b, buf, len);
567 	free(b);
568 	return (DLADM_STATUS_OK);
569 }
570 
571 
572 static dladm_status_t
573 dladm_vnic_persist_conf(dladm_handle_t handle, const char *name,
574     dladm_vnic_attr_t *attrp, datalink_class_t class)
575 {
576 	dladm_conf_t conf = DLADM_INVALID_CONF;
577 	dladm_status_t status;
578 	char macstr[ETHERADDRL * 3];
579 	uint64_t u64;
580 
581 	if ((status = dladm_create_conf(handle, name, attrp->va_vnic_id,
582 	    class, DL_ETHER, &conf)) != DLADM_STATUS_OK)
583 		return (status);
584 
585 	if (attrp->va_link_id != DATALINK_INVALID_LINKID) {
586 		u64 = attrp->va_link_id;
587 		status = dladm_set_conf_field(handle, conf, FLINKOVER,
588 		    DLADM_TYPE_UINT64, &u64);
589 		if (status != DLADM_STATUS_OK)
590 			goto done;
591 	}
592 
593 	if (class != DATALINK_CLASS_VLAN) {
594 		u64 = attrp->va_mac_addr_type;
595 		status = dladm_set_conf_field(handle, conf, FMADDRTYPE,
596 		    DLADM_TYPE_UINT64, &u64);
597 		if (status != DLADM_STATUS_OK)
598 			goto done;
599 
600 		if (attrp->va_mac_len != ETHERADDRL) {
601 			u64 = attrp->va_mac_len;
602 			status = dladm_set_conf_field(handle, conf, FMADDRLEN,
603 			    DLADM_TYPE_UINT64, &u64);
604 			if (status != DLADM_STATUS_OK)
605 				goto done;
606 		}
607 	}
608 
609 	if (attrp->va_hwrings) {
610 		boolean_t hwrings = attrp->va_hwrings;
611 		status = dladm_set_conf_field(handle, conf, FHWRINGS,
612 		    DLADM_TYPE_BOOLEAN, &hwrings);
613 		if (status != DLADM_STATUS_OK)
614 			goto done;
615 	}
616 
617 	if (class != DATALINK_CLASS_VLAN) {
618 		if (attrp->va_mac_slot != -1) {
619 			u64 = attrp->va_mac_slot;
620 			status = dladm_set_conf_field(handle, conf, FMADDRSLOT,
621 			    DLADM_TYPE_UINT64, &u64);
622 			if (status != DLADM_STATUS_OK)
623 			goto done;
624 		}
625 
626 		if (attrp->va_mac_prefix_len !=
627 		    sizeof (dladm_vnic_def_prefix)) {
628 			u64 = attrp->va_mac_prefix_len;
629 			status = dladm_set_conf_field(handle, conf,
630 			    FMADDRPREFIXLEN, DLADM_TYPE_UINT64, &u64);
631 			if (status != DLADM_STATUS_OK)
632 				goto done;
633 		}
634 
635 		(void) dladm_vnic_macaddr2str(attrp->va_mac_addr, macstr);
636 		status = dladm_set_conf_field(handle, conf, FMACADDR,
637 		    DLADM_TYPE_STR, macstr);
638 		if (status != DLADM_STATUS_OK)
639 			goto done;
640 	}
641 
642 	if (attrp->va_vid != 0) {
643 		u64 = attrp->va_vid;
644 		status = dladm_set_conf_field(handle, conf, FVLANID,
645 		    DLADM_TYPE_UINT64, &u64);
646 		if (status != DLADM_STATUS_OK)
647 			goto done;
648 	}
649 
650 	/*
651 	 * Commit the link configuration.
652 	 */
653 	status = dladm_write_conf(handle, conf);
654 
655 done:
656 	dladm_destroy_conf(handle, conf);
657 	return (status);
658 }
659 
660 typedef struct dladm_vnic_up_arg_s {
661 	uint32_t	flags;
662 	dladm_status_t	status;
663 } dladm_vnic_up_arg_t;
664 
665 #define	DLADM_VNIC_UP_FIRST_WALK	0x1
666 #define	DLADM_VNIC_UP_SECOND_WALK	0x2
667 
668 static int
669 i_dladm_vnic_up(dladm_handle_t handle, datalink_id_t linkid, void *arg)
670 {
671 	dladm_status_t *statusp = &(((dladm_vnic_up_arg_t *)arg)->status);
672 	dladm_vnic_attr_t attr;
673 	dladm_status_t status;
674 	dladm_arg_list_t *proplist;
675 	uint32_t flags = ((dladm_vnic_up_arg_t *)arg)->flags;
676 
677 	bzero(&attr, sizeof (attr));
678 
679 	status = dladm_vnic_info(handle, linkid, &attr, DLADM_OPT_PERSIST);
680 	if (status != DLADM_STATUS_OK)
681 		goto done;
682 
683 	/*
684 	 * Create the vnics that request hardware group first
685 	 * Create the vnics that don't request hardware group in the second walk
686 	 */
687 	if ((flags == DLADM_VNIC_UP_FIRST_WALK && !attr.va_hwrings) ||
688 	    (flags == DLADM_VNIC_UP_SECOND_WALK && attr.va_hwrings))
689 			goto done;
690 
691 	/* Get all properties for this vnic */
692 	status = dladm_link_get_proplist(handle, linkid, &proplist);
693 	if (status != DLADM_STATUS_OK)
694 		goto done;
695 
696 	if (proplist != NULL) {
697 		status = dladm_link_proplist_extract(handle, proplist,
698 		    &attr.va_resource_props);
699 	}
700 
701 	status = i_dladm_vnic_create_sys(handle, &attr);
702 	if (status != DLADM_STATUS_OK)
703 		goto done;
704 
705 	if ((status = dladm_up_datalink_id(handle, linkid)) !=
706 	    DLADM_STATUS_OK) {
707 		(void) i_dladm_vnic_delete_sys(handle, linkid);
708 		goto done;
709 	}
710 done:
711 	*statusp = status;
712 	return (DLADM_WALK_CONTINUE);
713 }
714 
715 dladm_status_t
716 dladm_vnic_up(dladm_handle_t handle, datalink_id_t linkid, uint32_t flags)
717 {
718 	dladm_vnic_up_arg_t vnic_arg;
719 	datalink_class_t class;
720 
721 	class = ((flags & DLADM_OPT_VLAN) != 0) ? DATALINK_CLASS_VLAN :
722 	    (DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB);
723 
724 	if (linkid == DATALINK_ALL_LINKID) {
725 		vnic_arg.flags = DLADM_VNIC_UP_FIRST_WALK;
726 		(void) dladm_walk_datalink_id(i_dladm_vnic_up, handle,
727 		    &vnic_arg, class, DATALINK_ANY_MEDIATYPE,
728 		    DLADM_OPT_PERSIST);
729 		vnic_arg.flags = DLADM_VNIC_UP_SECOND_WALK;
730 		(void) dladm_walk_datalink_id(i_dladm_vnic_up, handle,
731 		    &vnic_arg, class, DATALINK_ANY_MEDIATYPE,
732 		    DLADM_OPT_PERSIST);
733 		return (DLADM_STATUS_OK);
734 	} else {
735 		(void) i_dladm_vnic_up(handle, linkid, &vnic_arg);
736 		return (vnic_arg.status);
737 	}
738 }
739