xref: /illumos-gate/usr/src/lib/libdladm/common/libdlmgmt.c (revision a57549b4a2006e67bc7e247816f7ccd7fb62fce6)
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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright 2016 Joyent, Inc.
24  * Copyright 2023 Oxide Computer Company
25  */
26 
27 #include <door.h>
28 #include <errno.h>
29 #include <assert.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <strings.h>
35 #include <zone.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <sys/aggr.h>
39 #include <sys/mman.h>
40 #include <fcntl.h>
41 #include <libdladm.h>
42 #include <libdladm_impl.h>
43 #include <libdllink.h>
44 #include <libdlmgmt.h>
45 
46 /*
47  * Table of data type sizes indexed by dladm_datatype_t.
48  */
49 static size_t dladm_datatype_size[] = {
50 	0,				/* DLADM_TYPE_STR, use strnlen() */
51 	sizeof (boolean_t),		/* DLADM_TYPE_BOOLEAN */
52 	sizeof (uint64_t)		/* DLADM_TYPE_UINT64 */
53 };
54 
55 static dladm_status_t
56 dladm_door_call(dladm_handle_t handle, void *arg, size_t asize, void *rbuf,
57     size_t *rsizep)
58 {
59 	door_arg_t	darg;
60 	int		door_fd;
61 	dladm_status_t	status;
62 	boolean_t	reopen = B_FALSE;
63 
64 	darg.data_ptr	= arg;
65 	darg.data_size	= asize;
66 	darg.desc_ptr	= NULL;
67 	darg.desc_num	= 0;
68 	darg.rbuf	= rbuf;
69 	darg.rsize	= *rsizep;
70 
71 reopen:
72 	/* The door descriptor is opened if it isn't already */
73 	if ((status = dladm_door_fd(handle, &door_fd)) != DLADM_STATUS_OK)
74 		return (status);
75 	if (door_call(door_fd, &darg) == -1) {
76 		/*
77 		 * Stale door descriptor is possible if dlmgmtd was re-started
78 		 * since last door_fd open so try re-opening door file.
79 		 */
80 		if (!reopen && errno == EBADF) {
81 			(void) close(handle->door_fd);
82 			handle->door_fd = -1;
83 			reopen = B_TRUE;
84 			goto reopen;
85 		}
86 		status = dladm_errno2status(errno);
87 	}
88 	if (status != DLADM_STATUS_OK)
89 		return (status);
90 
91 	if (darg.rbuf != rbuf) {
92 		/*
93 		 * The size of the input rbuf is not big enough so that
94 		 * the door allocate the rbuf itself. In this case, return
95 		 * the required size to the caller.
96 		 */
97 		(void) munmap(darg.rbuf, darg.rsize);
98 		*rsizep = darg.rsize;
99 		return (DLADM_STATUS_TOOSMALL);
100 	} else if (darg.rsize != *rsizep) {
101 		return (DLADM_STATUS_FAILED);
102 	}
103 
104 	return (dladm_errno2status(((dlmgmt_retval_t *)rbuf)->lr_err));
105 }
106 
107 /*
108  * Allocate a new linkid with the given name. Return the new linkid.
109  */
110 dladm_status_t
111 dladm_create_datalink_id(dladm_handle_t handle, const char *link,
112     datalink_class_t class, uint32_t media, uint32_t flags,
113     datalink_id_t *linkidp)
114 {
115 	dlmgmt_door_createid_t	createid;
116 	dlmgmt_createid_retval_t retval;
117 	uint32_t		dlmgmt_flags;
118 	dladm_status_t		status;
119 	size_t			sz = sizeof (retval);
120 
121 	if (link == NULL || class == DATALINK_CLASS_ALL ||
122 	    !(flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST)) ||
123 	    linkidp == NULL) {
124 		return (DLADM_STATUS_BADARG);
125 	}
126 
127 	if (getzoneid() != GLOBAL_ZONEID) {
128 		/*
129 		 * If we're creating this link in a non-global zone, then do
130 		 * not allow it to be persistent, and flag it as transient so
131 		 * that it will be automatically cleaned up on zone shutdown,
132 		 * rather than being moved to the GZ.
133 		 */
134 		if (flags & DLADM_OPT_PERSIST)
135 			return (DLADM_STATUS_TEMPONLY);
136 		flags |= DLADM_OPT_TRANSIENT;
137 	}
138 
139 	dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0;
140 	dlmgmt_flags |= (flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0;
141 	dlmgmt_flags |= (flags & DLADM_OPT_TRANSIENT) ? DLMGMT_TRANSIENT : 0;
142 
143 	(void) strlcpy(createid.ld_link, link, MAXLINKNAMELEN);
144 	createid.ld_class = class;
145 	createid.ld_media = media;
146 	createid.ld_flags = dlmgmt_flags;
147 	createid.ld_cmd = DLMGMT_CMD_CREATE_LINKID;
148 	createid.ld_prefix = (flags & DLADM_OPT_PREFIX);
149 
150 	if ((status = dladm_door_call(handle, &createid, sizeof (createid),
151 	    &retval, &sz)) == DLADM_STATUS_OK) {
152 		*linkidp = retval.lr_linkid;
153 	}
154 	return (status);
155 }
156 
157 /*
158  * Destroy the given link ID.
159  */
160 dladm_status_t
161 dladm_destroy_datalink_id(dladm_handle_t handle, datalink_id_t linkid,
162     uint32_t flags)
163 {
164 	dlmgmt_door_destroyid_t		destroyid;
165 	dlmgmt_destroyid_retval_t	retval;
166 	uint32_t			dlmgmt_flags;
167 	size_t				sz = sizeof (retval);
168 
169 	dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0;
170 	dlmgmt_flags |= ((flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0);
171 
172 	destroyid.ld_cmd = DLMGMT_CMD_DESTROY_LINKID;
173 	destroyid.ld_linkid = linkid;
174 	destroyid.ld_flags = dlmgmt_flags;
175 
176 	return (dladm_door_call(handle, &destroyid, sizeof (destroyid),
177 	    &retval, &sz));
178 }
179 
180 /*
181  * Remap a given link ID to a new name.
182  */
183 dladm_status_t
184 dladm_remap_datalink_id(dladm_handle_t handle, datalink_id_t linkid,
185     const char *link)
186 {
187 	dlmgmt_door_remapid_t	remapid;
188 	dlmgmt_remapid_retval_t	retval;
189 	size_t			sz = sizeof (retval);
190 
191 	remapid.ld_cmd = DLMGMT_CMD_REMAP_LINKID;
192 	remapid.ld_linkid = linkid;
193 	(void) strlcpy(remapid.ld_link, link, MAXLINKNAMELEN);
194 
195 	return (dladm_door_call(handle, &remapid, sizeof (remapid),
196 	    &retval, &sz));
197 }
198 
199 /*
200  * Make a given link ID active.
201  */
202 dladm_status_t
203 dladm_up_datalink_id(dladm_handle_t handle, datalink_id_t linkid)
204 {
205 	dlmgmt_door_upid_t	upid;
206 	dlmgmt_upid_retval_t	retval;
207 	size_t			sz = sizeof (retval);
208 
209 	upid.ld_cmd = DLMGMT_CMD_UP_LINKID;
210 	upid.ld_linkid = linkid;
211 
212 	return (dladm_door_call(handle, &upid, sizeof (upid), &retval, &sz));
213 }
214 
215 /*
216  * Create a new link with the given name.  Return the new link's handle
217  */
218 dladm_status_t
219 dladm_create_conf(dladm_handle_t handle, const char *link, datalink_id_t linkid,
220     datalink_class_t class, uint32_t media, dladm_conf_t *confp)
221 {
222 	dlmgmt_door_createconf_t	createconf;
223 	dlmgmt_createconf_retval_t	retval;
224 	dladm_status_t			status;
225 	size_t				sz = sizeof (retval);
226 
227 	if (link == NULL || confp == NULL)
228 		return (DLADM_STATUS_BADARG);
229 
230 	(void) strlcpy(createconf.ld_link, link, MAXLINKNAMELEN);
231 	createconf.ld_class = class;
232 	createconf.ld_media = media;
233 	createconf.ld_linkid = linkid;
234 	createconf.ld_cmd = DLMGMT_CMD_CREATECONF;
235 	confp->ds_confid = DLADM_INVALID_CONF;
236 
237 	if ((status = dladm_door_call(handle, &createconf, sizeof (createconf),
238 	    &retval, &sz)) == DLADM_STATUS_OK) {
239 		confp->ds_readonly = B_FALSE;
240 		confp->ds_confid = retval.lr_confid;
241 	}
242 	return (status);
243 }
244 
245 /*
246  * An active physical link reported by the dlmgmtd daemon might not be active
247  * anymore as this link might be removed during system shutdown. Check its
248  * real status by calling dladm_phys_info().
249  */
250 dladm_status_t
251 i_dladm_phys_status(dladm_handle_t handle, datalink_id_t linkid,
252     uint32_t *flagsp)
253 {
254 	dladm_phys_attr_t	dpa;
255 	dladm_status_t		status;
256 
257 	assert((*flagsp) & DLMGMT_ACTIVE);
258 
259 	status = dladm_phys_info(handle, linkid, &dpa, DLADM_OPT_ACTIVE);
260 	if (status == DLADM_STATUS_NOTFOUND) {
261 		/*
262 		 * No active status, this link was removed. Update its status
263 		 * in the daemon and delete all active linkprops.
264 		 *
265 		 * Note that the operation could fail. If it does, return
266 		 * failure now since otherwise dladm_set_linkprop() might
267 		 * call back to i_dladm_phys_status() recursively.
268 		 */
269 		if ((status = dladm_destroy_datalink_id(handle, linkid,
270 		    DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK)
271 			return (status);
272 
273 		(void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0,
274 		    DLADM_OPT_ACTIVE);
275 
276 		(*flagsp) &= ~DLMGMT_ACTIVE;
277 		status = DLADM_STATUS_OK;
278 	}
279 	return (status);
280 }
281 
282 /*
283  * Walk each entry in the data link configuration repository and
284  * call fn on the linkid and arg.
285  */
286 dladm_status_t
287 dladm_walk_datalink_id(int (*fn)(dladm_handle_t, datalink_id_t, void *),
288     dladm_handle_t handle, void *argp, datalink_class_t class,
289     datalink_media_t dmedia, uint32_t flags)
290 {
291 	dlmgmt_door_getnext_t	getnext;
292 	dlmgmt_getnext_retval_t	retval;
293 	uint32_t		dlmgmt_flags;
294 	datalink_id_t		linkid = DATALINK_INVALID_LINKID;
295 	dladm_status_t		status = DLADM_STATUS_OK;
296 	size_t			sz = sizeof (retval);
297 
298 	if (fn == NULL)
299 		return (DLADM_STATUS_BADARG);
300 
301 	dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0;
302 	dlmgmt_flags |= ((flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0);
303 	dlmgmt_flags |= ((flags & DLADM_OPT_TRANSIENT) ? DLMGMT_TRANSIENT : 0);
304 
305 	getnext.ld_cmd = DLMGMT_CMD_GETNEXT;
306 	getnext.ld_class = class;
307 	getnext.ld_dmedia = dmedia;
308 	getnext.ld_flags = dlmgmt_flags;
309 
310 	do {
311 		getnext.ld_linkid = linkid;
312 		if ((status = dladm_door_call(handle, &getnext,
313 		    sizeof (getnext), &retval, &sz)) != DLADM_STATUS_OK) {
314 			/*
315 			 * Done with walking. If no next datalink is found,
316 			 * return success.
317 			 */
318 			if (status == DLADM_STATUS_NOTFOUND)
319 				status = DLADM_STATUS_OK;
320 			break;
321 		}
322 
323 		linkid = retval.lr_linkid;
324 		if ((retval.lr_class == DATALINK_CLASS_PHYS) &&
325 		    (retval.lr_flags & DLMGMT_ACTIVE)) {
326 			/*
327 			 * An active physical link reported by the dlmgmtd
328 			 * daemon might not be active anymore. Check its
329 			 * real status.
330 			 */
331 			if (i_dladm_phys_status(handle, linkid,
332 			    &retval.lr_flags) != DLADM_STATUS_OK) {
333 				continue;
334 			}
335 
336 			if (!(dlmgmt_flags & retval.lr_flags))
337 				continue;
338 		}
339 
340 		if (fn(handle, linkid, argp) == DLADM_WALK_TERMINATE)
341 			break;
342 	} while (linkid != DATALINK_INVALID_LINKID);
343 
344 	return (status);
345 }
346 
347 /*
348  * Get a handle of a copy of the link configuration (kept in the daemon)
349  * for the given link so it can be updated later by dladm_write_conf().
350  */
351 dladm_status_t
352 dladm_open_conf(dladm_handle_t handle, datalink_id_t linkid,
353     dladm_conf_t *confp)
354 {
355 	dlmgmt_door_openconf_t		openconf;
356 	dlmgmt_openconf_retval_t	retval;
357 	dladm_status_t			status;
358 	size_t				sz;
359 
360 	if (linkid == DATALINK_INVALID_LINKID || confp == NULL)
361 		return (DLADM_STATUS_BADARG);
362 
363 	sz = sizeof (retval);
364 	openconf.ld_linkid = linkid;
365 	openconf.ld_cmd = DLMGMT_CMD_OPENCONF;
366 	confp->ds_confid = DLADM_INVALID_CONF;
367 	if ((status = dladm_door_call(handle, &openconf,
368 	    sizeof (openconf), &retval, &sz)) == DLADM_STATUS_OK) {
369 		confp->ds_readonly = B_FALSE;
370 		confp->ds_confid = retval.lr_confid;
371 	}
372 
373 	return (status);
374 }
375 
376 /*
377  * Get the handle of a local snapshot of the link configuration. Note that
378  * any operations with this handle are read-only, i.e., one can not update
379  * the configuration with this handle.
380  */
381 dladm_status_t
382 dladm_getsnap_conf(dladm_handle_t handle, datalink_id_t linkid,
383     dladm_conf_t *confp)
384 {
385 	dlmgmt_door_getconfsnapshot_t	snapshot;
386 	dlmgmt_getconfsnapshot_retval_t	*retvalp;
387 	char				*nvlbuf;
388 	dladm_status_t			status;
389 	int				err;
390 	size_t				sz;
391 
392 	if (linkid == DATALINK_INVALID_LINKID || confp == NULL)
393 		return (DLADM_STATUS_BADARG);
394 
395 	sz = sizeof (dlmgmt_getconfsnapshot_retval_t);
396 	snapshot.ld_linkid = linkid;
397 	snapshot.ld_cmd = DLMGMT_CMD_GETCONFSNAPSHOT;
398 again:
399 	if ((retvalp = malloc(sz)) == NULL)
400 		return (DLADM_STATUS_NOMEM);
401 
402 	if ((status = dladm_door_call(handle, &snapshot, sizeof (snapshot),
403 	    retvalp, &sz)) == DLADM_STATUS_TOOSMALL) {
404 		free(retvalp);
405 		goto again;
406 	}
407 
408 	if (status != DLADM_STATUS_OK) {
409 		free(retvalp);
410 		return (status);
411 	}
412 
413 	confp->ds_readonly = B_TRUE;
414 	nvlbuf = (char *)retvalp + sizeof (dlmgmt_getconfsnapshot_retval_t);
415 	if ((err = nvlist_unpack(nvlbuf, retvalp->lr_nvlsz,
416 	    &(confp->ds_nvl), 0)) != 0) {
417 		status = dladm_errno2status(err);
418 	}
419 	free(retvalp);
420 	return (status);
421 }
422 
423 /*
424  * Commit the given link to the data link configuration repository so
425  * that it will persist across reboots.
426  */
427 dladm_status_t
428 dladm_write_conf(dladm_handle_t handle, dladm_conf_t conf)
429 {
430 	dlmgmt_door_writeconf_t		writeconf;
431 	dlmgmt_writeconf_retval_t	retval;
432 	size_t				sz = sizeof (retval);
433 
434 	if (conf.ds_confid == DLADM_INVALID_CONF)
435 		return (DLADM_STATUS_BADARG);
436 
437 	if (conf.ds_readonly)
438 		return (DLADM_STATUS_DENIED);
439 
440 	writeconf.ld_cmd = DLMGMT_CMD_WRITECONF;
441 	writeconf.ld_confid = conf.ds_confid;
442 
443 	return (dladm_door_call(handle, &writeconf, sizeof (writeconf),
444 	    &retval, &sz));
445 }
446 
447 /*
448  * Given a dladm_conf_t, get the specific configuration field
449  *
450  * If the specified dladm_conf_t is a read-only snapshot of the configuration,
451  * get a specific link propertie from that snapshot (nvl), otherwise, get
452  * the link protperty from the dlmgmtd daemon using the given confid.
453  */
454 dladm_status_t
455 dladm_get_conf_field(dladm_handle_t handle, dladm_conf_t conf, const char *attr,
456     void *attrval, size_t attrsz)
457 {
458 	dladm_status_t		status = DLADM_STATUS_OK;
459 
460 	if (attrval == NULL || attrsz == 0 || attr == NULL)
461 		return (DLADM_STATUS_BADARG);
462 
463 	if (conf.ds_readonly) {
464 		uchar_t		*oattrval;
465 		uint32_t	oattrsz;
466 		int		err;
467 
468 		if ((err = nvlist_lookup_byte_array(conf.ds_nvl, (char *)attr,
469 		    &oattrval, &oattrsz)) != 0) {
470 			return (dladm_errno2status(err));
471 		}
472 		if (oattrsz > attrsz)
473 			return (DLADM_STATUS_TOOSMALL);
474 
475 		bcopy(oattrval, attrval, oattrsz);
476 	} else {
477 		dlmgmt_door_getattr_t	getattr;
478 		dlmgmt_getattr_retval_t	retval;
479 		size_t			sz = sizeof (retval);
480 
481 		if (conf.ds_confid == DLADM_INVALID_CONF)
482 			return (DLADM_STATUS_BADARG);
483 
484 		getattr.ld_cmd = DLMGMT_CMD_GETATTR;
485 		getattr.ld_confid = conf.ds_confid;
486 		(void) strlcpy(getattr.ld_attr, attr, MAXLINKATTRLEN);
487 
488 		if ((status = dladm_door_call(handle, &getattr,
489 		    sizeof (getattr), &retval, &sz)) != DLADM_STATUS_OK) {
490 			return (status);
491 		}
492 
493 		if (retval.lr_attrsz > attrsz)
494 			return (DLADM_STATUS_TOOSMALL);
495 
496 		bcopy(retval.lr_attrval, attrval, retval.lr_attrsz);
497 	}
498 	return (status);
499 }
500 
501 /*
502  * Get next property attribute from data link configuration repository.
503  * If last_attr is "", return the first property.
504  */
505 dladm_status_t
506 dladm_getnext_conf_linkprop(dladm_handle_t handle __unused, dladm_conf_t conf,
507     const char *last_attr, char *attr, void *attrval, size_t attrsz,
508     size_t *attrszp)
509 {
510 	nvlist_t	*nvl = conf.ds_nvl;
511 	nvpair_t	*last = NULL, *nvp;
512 	uchar_t		*oattrval;
513 	uint32_t	oattrsz;
514 	int		err;
515 
516 	if (nvl == NULL || attrval == NULL || attrsz == 0 || attr == NULL ||
517 	    !conf.ds_readonly)
518 		return (DLADM_STATUS_BADARG);
519 
520 	while ((nvp = nvlist_next_nvpair(nvl, last)) != NULL) {
521 		if (last_attr[0] == '\0')
522 			break;
523 		if (last != NULL && strcmp(last_attr, nvpair_name(last)) == 0)
524 			break;
525 		last = nvp;
526 	}
527 
528 	if (nvp == NULL)
529 		return (DLADM_STATUS_NOTFOUND);
530 
531 	if ((err = nvpair_value_byte_array(nvp, (uchar_t **)&oattrval,
532 	    &oattrsz)) != 0) {
533 		return (dladm_errno2status(err));
534 	}
535 
536 	*attrszp = oattrsz;
537 	if (oattrsz > attrsz)
538 		return (DLADM_STATUS_TOOSMALL);
539 
540 	(void) strlcpy(attr, nvpair_name(nvp), MAXLINKATTRLEN);
541 	bcopy(oattrval, attrval, oattrsz);
542 	return (DLADM_STATUS_OK);
543 }
544 
545 /*
546  * Get the link ID that is associated with the given name.
547  */
548 dladm_status_t
549 dladm_name2info(dladm_handle_t handle, const char *link, datalink_id_t *linkidp,
550     uint32_t *flagp, datalink_class_t *classp, uint32_t *mediap)
551 {
552 	dlmgmt_door_getlinkid_t		getlinkid;
553 	dlmgmt_getlinkid_retval_t	retval;
554 	datalink_id_t			linkid;
555 	dladm_status_t			status;
556 	size_t				sz = sizeof (retval);
557 
558 	getlinkid.ld_cmd = DLMGMT_CMD_GETLINKID;
559 	(void) strlcpy(getlinkid.ld_link, link, MAXLINKNAMELEN);
560 
561 	if ((status = dladm_door_call(handle, &getlinkid, sizeof (getlinkid),
562 	    &retval, &sz)) != DLADM_STATUS_OK) {
563 		return (status);
564 	}
565 
566 	linkid = retval.lr_linkid;
567 	if (retval.lr_class == DATALINK_CLASS_PHYS &&
568 	    retval.lr_flags & DLMGMT_ACTIVE) {
569 		/*
570 		 * An active physical link reported by the dlmgmtd daemon
571 		 * might not be active anymore. Check and set its real status.
572 		 */
573 		status = i_dladm_phys_status(handle, linkid, &retval.lr_flags);
574 		if (status != DLADM_STATUS_OK)
575 			return (status);
576 	}
577 
578 	if (linkidp != NULL)
579 		*linkidp = linkid;
580 	if (flagp != NULL) {
581 		*flagp = (retval.lr_flags & DLMGMT_ACTIVE) ?
582 		    DLADM_OPT_ACTIVE : 0;
583 		*flagp |= (retval.lr_flags & DLMGMT_PERSIST) ?
584 		    DLADM_OPT_PERSIST : 0;
585 		*flagp |= (retval.lr_flags & DLMGMT_TRANSIENT) ?
586 		    DLADM_OPT_TRANSIENT : 0;
587 	}
588 	if (classp != NULL)
589 		*classp = retval.lr_class;
590 	if (mediap != NULL)
591 		*mediap = retval.lr_media;
592 
593 	return (DLADM_STATUS_OK);
594 }
595 
596 /*
597  * Get the link name that is associated with the given id.
598  */
599 dladm_status_t
600 dladm_datalink_id2info(dladm_handle_t handle, datalink_id_t linkid,
601     uint32_t *flagp, datalink_class_t *classp, uint32_t *mediap, char *link,
602     size_t len)
603 {
604 	dlmgmt_door_getname_t	getname;
605 	dlmgmt_getname_retval_t	retval;
606 	dladm_status_t		status;
607 	size_t			sz = sizeof (retval);
608 
609 	if ((linkid == DATALINK_INVALID_LINKID) || (link != NULL && len == 0) ||
610 	    (link == NULL && len != 0)) {
611 		return (DLADM_STATUS_BADARG);
612 	}
613 
614 	getname.ld_cmd = DLMGMT_CMD_GETNAME;
615 	getname.ld_linkid = linkid;
616 	if ((status = dladm_door_call(handle, &getname, sizeof (getname),
617 	    &retval, &sz)) != DLADM_STATUS_OK) {
618 		return (status);
619 	}
620 
621 	if (len != 0 && (strlen(retval.lr_link) + 1 > len))
622 		return (DLADM_STATUS_TOOSMALL);
623 
624 	if (retval.lr_class == DATALINK_CLASS_PHYS &&
625 	    retval.lr_flags & DLMGMT_ACTIVE) {
626 		/*
627 		 * An active physical link reported by the dlmgmtd daemon
628 		 * might not be active anymore. Check and set its real status.
629 		 */
630 		status = i_dladm_phys_status(handle, linkid, &retval.lr_flags);
631 		if (status != DLADM_STATUS_OK)
632 			return (status);
633 	}
634 
635 	if (link != NULL)
636 		(void) strlcpy(link, retval.lr_link, len);
637 	if (classp != NULL)
638 		*classp = retval.lr_class;
639 	if (mediap != NULL)
640 		*mediap = retval.lr_media;
641 	if (flagp != NULL) {
642 		*flagp = (retval.lr_flags & DLMGMT_ACTIVE) ?
643 		    DLADM_OPT_ACTIVE : 0;
644 		*flagp |= (retval.lr_flags & DLMGMT_PERSIST) ?
645 		    DLADM_OPT_PERSIST : 0;
646 		*flagp |= (retval.lr_flags & DLMGMT_TRANSIENT) ?
647 		    DLADM_OPT_TRANSIENT : 0;
648 	}
649 	return (DLADM_STATUS_OK);
650 }
651 
652 /*
653  * Set the given attr with the given attrval for the given link.
654  */
655 dladm_status_t
656 dladm_set_conf_field(dladm_handle_t handle, dladm_conf_t conf, const char *attr,
657     dladm_datatype_t type, const void *attrval)
658 {
659 	dlmgmt_door_setattr_t	setattr;
660 	dlmgmt_setattr_retval_t	retval;
661 	size_t			attrsz;
662 	size_t			sz = sizeof (retval);
663 
664 	if (attr == NULL || attrval == NULL)
665 		return (DLADM_STATUS_BADARG);
666 
667 	if (conf.ds_readonly)
668 		return (DLADM_STATUS_DENIED);
669 
670 	if (type == DLADM_TYPE_STR)
671 		attrsz = strlen(attrval) + 1;
672 	else
673 		attrsz = dladm_datatype_size[type];
674 
675 	if (attrsz > MAXLINKATTRVALLEN)
676 		return (DLADM_STATUS_TOOSMALL);
677 
678 	setattr.ld_cmd = DLMGMT_CMD_SETATTR;
679 	setattr.ld_confid = conf.ds_confid;
680 	(void) strlcpy(setattr.ld_attr, attr, MAXLINKATTRLEN);
681 	setattr.ld_attrsz = (uint32_t)attrsz;
682 	setattr.ld_type = type;
683 	bcopy(attrval, &setattr.ld_attrval, attrsz);
684 
685 	return (dladm_door_call(handle, &setattr, sizeof (setattr),
686 	    &retval, &sz));
687 }
688 
689 /*
690  * Unset the given attr the given link.
691  */
692 dladm_status_t
693 dladm_unset_conf_field(dladm_handle_t handle, dladm_conf_t conf,
694     const char *attr)
695 {
696 	dlmgmt_door_unsetattr_t		unsetattr;
697 	dlmgmt_unsetattr_retval_t	retval;
698 	size_t				sz = sizeof (retval);
699 
700 	if (attr == NULL)
701 		return (DLADM_STATUS_BADARG);
702 
703 	if (conf.ds_readonly)
704 		return (DLADM_STATUS_DENIED);
705 
706 	unsetattr.ld_cmd = DLMGMT_CMD_UNSETATTR;
707 	unsetattr.ld_confid = conf.ds_confid;
708 	(void) strlcpy(unsetattr.ld_attr, attr, MAXLINKATTRLEN);
709 
710 	return (dladm_door_call(handle, &unsetattr, sizeof (unsetattr),
711 	    &retval, &sz));
712 }
713 
714 /*
715  * Remove the given link ID and its entry from the data link configuration
716  * repository.
717  */
718 dladm_status_t
719 dladm_remove_conf(dladm_handle_t handle, datalink_id_t linkid)
720 {
721 	dlmgmt_door_removeconf_t	removeconf;
722 	dlmgmt_removeconf_retval_t	retval;
723 	size_t				sz = sizeof (retval);
724 
725 	removeconf.ld_cmd = DLMGMT_CMD_REMOVECONF;
726 	removeconf.ld_linkid = linkid;
727 
728 	return (dladm_door_call(handle, &removeconf, sizeof (removeconf),
729 	    &retval, &sz));
730 }
731 
732 /*
733  * Free the contents of the link structure.
734  */
735 void
736 dladm_destroy_conf(dladm_handle_t handle, dladm_conf_t conf)
737 {
738 	dlmgmt_door_destroyconf_t	dconf;
739 	dlmgmt_destroyconf_retval_t	retval;
740 	size_t				sz = sizeof (retval);
741 
742 	if (conf.ds_readonly) {
743 		nvlist_free(conf.ds_nvl);
744 	} else {
745 		if (conf.ds_confid == DLADM_INVALID_CONF)
746 			return;
747 
748 		dconf.ld_cmd = DLMGMT_CMD_DESTROYCONF;
749 		dconf.ld_confid = conf.ds_confid;
750 
751 		(void) dladm_door_call(handle, &dconf, sizeof (dconf),
752 		    &retval, &sz);
753 	}
754 }
755 
756 dladm_status_t
757 dladm_zone_boot(dladm_handle_t handle, zoneid_t zoneid)
758 {
759 	dlmgmt_door_zoneboot_t		zoneboot;
760 	dlmgmt_zoneboot_retval_t	retval;
761 	size_t				sz = sizeof (retval);
762 
763 	zoneboot.ld_cmd = DLMGMT_CMD_ZONEBOOT;
764 	zoneboot.ld_zoneid = zoneid;
765 	return (dladm_door_call(handle, &zoneboot, sizeof (zoneboot),
766 	    &retval, &sz));
767 }
768 
769 dladm_status_t
770 dladm_zone_halt(dladm_handle_t handle, zoneid_t zoneid)
771 {
772 	dlmgmt_door_zonehalt_t		zonehalt;
773 	dlmgmt_zonehalt_retval_t	retval;
774 	size_t				sz = sizeof (retval);
775 
776 	zonehalt.ld_cmd = DLMGMT_CMD_ZONEHALT;
777 	zonehalt.ld_zoneid = zoneid;
778 	return (dladm_door_call(handle, &zonehalt, sizeof (zonehalt),
779 	    &retval, &sz));
780 }
781