xref: /illumos-gate/usr/src/lib/libdladm/common/libdlmgmt.c (revision 7a088f03b431bdffa96c3b2175964d4d38420caa)
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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <door.h>
27 #include <errno.h>
28 #include <assert.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <strings.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <sys/aggr.h>
37 #include <sys/mman.h>
38 #include <fcntl.h>
39 #include <libdladm.h>
40 #include <libdladm_impl.h>
41 #include <libdllink.h>
42 #include <libdlmgmt.h>
43 
44 /*
45  * Table of data type sizes indexed by dladm_datatype_t.
46  */
47 static size_t dladm_datatype_size[] = {
48 	0,				/* DLADM_TYPE_STR, use strnlen() */
49 	sizeof (boolean_t),		/* DLADM_TYPE_BOOLEAN */
50 	sizeof (uint64_t)		/* DLADM_TYPE_UINT64 */
51 };
52 
53 static dladm_status_t
54 dladm_door_call(dladm_handle_t handle, void *arg, size_t asize, void *rbuf,
55     size_t rsize)
56 {
57 	door_arg_t	darg;
58 	int		door_fd;
59 	dladm_status_t	status = DLADM_STATUS_OK;
60 
61 	darg.data_ptr	= arg;
62 	darg.data_size	= asize;
63 	darg.desc_ptr	= NULL;
64 	darg.desc_num	= 0;
65 	darg.rbuf	= rbuf;
66 	darg.rsize	= rsize;
67 
68 	/* The door descriptor is opened if it isn't already */
69 	if ((status = dladm_door_fd(handle, &door_fd)) != DLADM_STATUS_OK)
70 		return (status);
71 	if (door_call(door_fd, &darg) == -1)
72 		status = dladm_errno2status(errno);
73 	if (status != DLADM_STATUS_OK)
74 		return (status);
75 
76 	if (darg.rbuf != rbuf) {
77 		/*
78 		 * The size of the input rbuf is not big enough so that
79 		 * the door allocate the rbuf itself. In this case, simply
80 		 * think something wrong with the door call.
81 		 */
82 		(void) munmap(darg.rbuf, darg.rsize);
83 		return (DLADM_STATUS_TOOSMALL);
84 	}
85 	if (darg.rsize != rsize)
86 		return (DLADM_STATUS_FAILED);
87 
88 	return (dladm_errno2status(((dlmgmt_retval_t *)rbuf)->lr_err));
89 }
90 
91 /*
92  * Allocate a new linkid with the given name. Return the new linkid.
93  */
94 dladm_status_t
95 dladm_create_datalink_id(dladm_handle_t handle, const char *link,
96     datalink_class_t class, uint32_t media, uint32_t flags,
97     datalink_id_t *linkidp)
98 {
99 	dlmgmt_door_createid_t	createid;
100 	dlmgmt_createid_retval_t retval;
101 	uint32_t		dlmgmt_flags;
102 	dladm_status_t		status;
103 
104 	if (link == NULL || class == DATALINK_CLASS_ALL ||
105 	    !(flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST)) ||
106 	    linkidp == NULL) {
107 		return (DLADM_STATUS_BADARG);
108 	}
109 
110 	dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0;
111 	dlmgmt_flags |= (flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0;
112 
113 	(void) strlcpy(createid.ld_link, link, MAXLINKNAMELEN);
114 	createid.ld_class = class;
115 	createid.ld_media = media;
116 	createid.ld_flags = dlmgmt_flags;
117 	createid.ld_cmd = DLMGMT_CMD_CREATE_LINKID;
118 	createid.ld_prefix = (flags & DLADM_OPT_PREFIX);
119 
120 	if ((status = dladm_door_call(handle, &createid, sizeof (createid),
121 	    &retval, sizeof (retval))) == DLADM_STATUS_OK) {
122 		*linkidp = retval.lr_linkid;
123 	}
124 	return (status);
125 }
126 
127 /*
128  * Destroy the given link ID.
129  */
130 dladm_status_t
131 dladm_destroy_datalink_id(dladm_handle_t handle, datalink_id_t linkid,
132     uint32_t flags)
133 {
134 	dlmgmt_door_destroyid_t		destroyid;
135 	dlmgmt_destroyid_retval_t	retval;
136 	uint32_t			dlmgmt_flags;
137 
138 	dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0;
139 	dlmgmt_flags |= ((flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0);
140 
141 	destroyid.ld_cmd = DLMGMT_CMD_DESTROY_LINKID;
142 	destroyid.ld_linkid = linkid;
143 	destroyid.ld_flags = dlmgmt_flags;
144 
145 	return (dladm_door_call(handle, &destroyid, sizeof (destroyid), &retval,
146 	    sizeof (retval)));
147 }
148 
149 /*
150  * Remap a given link ID to a new name.
151  */
152 dladm_status_t
153 dladm_remap_datalink_id(dladm_handle_t handle, datalink_id_t linkid,
154     const char *link)
155 {
156 	dlmgmt_door_remapid_t	remapid;
157 	dlmgmt_remapid_retval_t	retval;
158 
159 	remapid.ld_cmd = DLMGMT_CMD_REMAP_LINKID;
160 	remapid.ld_linkid = linkid;
161 	(void) strlcpy(remapid.ld_link, link, MAXLINKNAMELEN);
162 
163 	return (dladm_door_call(handle, &remapid, sizeof (remapid), &retval,
164 	    sizeof (retval)));
165 }
166 
167 /*
168  * Make a given link ID active.
169  */
170 dladm_status_t
171 dladm_up_datalink_id(dladm_handle_t handle, datalink_id_t linkid)
172 {
173 	dlmgmt_door_upid_t	upid;
174 	dlmgmt_upid_retval_t	retval;
175 
176 	upid.ld_cmd = DLMGMT_CMD_UP_LINKID;
177 	upid.ld_linkid = linkid;
178 
179 	return (dladm_door_call(handle, &upid, sizeof (upid), &retval,
180 	    sizeof (retval)));
181 }
182 
183 /*
184  * Create a new link with the given name.  Return the new link's handle
185  */
186 dladm_status_t
187 dladm_create_conf(dladm_handle_t handle, const char *link, datalink_id_t linkid,
188     datalink_class_t class, uint32_t media, dladm_conf_t *confp)
189 {
190 	dlmgmt_door_createconf_t	createconf;
191 	dlmgmt_createconf_retval_t	retval;
192 	dladm_status_t			status;
193 
194 	if (link == NULL || confp == NULL)
195 		return (DLADM_STATUS_BADARG);
196 
197 	(void) strlcpy(createconf.ld_link, link, MAXLINKNAMELEN);
198 	createconf.ld_class = class;
199 	createconf.ld_media = media;
200 	createconf.ld_linkid = linkid;
201 	createconf.ld_cmd = DLMGMT_CMD_CREATECONF;
202 
203 	if ((status = dladm_door_call(handle, &createconf, sizeof (createconf),
204 	    &retval, sizeof (retval))) == DLADM_STATUS_OK) {
205 		*confp = retval.lr_conf;
206 	}
207 	return (status);
208 }
209 
210 /*
211  * An active physical link reported by the dlmgmtd daemon might not be active
212  * anymore as this link might be removed during system shutdown. Check its
213  * real status by calling dladm_phys_info().
214  */
215 dladm_status_t
216 i_dladm_phys_status(dladm_handle_t handle, datalink_id_t linkid,
217     uint32_t *flagsp)
218 {
219 	dladm_phys_attr_t	dpa;
220 	dladm_status_t		status;
221 
222 	assert((*flagsp) & DLMGMT_ACTIVE);
223 
224 	status = dladm_phys_info(handle, linkid, &dpa, DLADM_OPT_ACTIVE);
225 	if (status == DLADM_STATUS_NOTFOUND) {
226 		/*
227 		 * No active status, this link was removed. Update its status
228 		 * in the daemon and delete all active linkprops.
229 		 *
230 		 * Note that the operation could fail. If it does, return
231 		 * failure now since otherwise dladm_set_linkprop() might
232 		 * call back to i_dladm_phys_status() recursively.
233 		 */
234 		if ((status = dladm_destroy_datalink_id(handle, linkid,
235 		    DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK)
236 			return (status);
237 
238 		(void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0,
239 		    DLADM_OPT_ACTIVE);
240 
241 		(*flagsp) &= ~DLMGMT_ACTIVE;
242 		status = DLADM_STATUS_OK;
243 	}
244 	return (status);
245 }
246 
247 /*
248  * Walk each entry in the data link configuration repository and
249  * call fn on the linkid and arg.
250  */
251 dladm_status_t
252 dladm_walk_datalink_id(int (*fn)(dladm_handle_t, datalink_id_t, void *),
253     dladm_handle_t handle, void *argp, datalink_class_t class,
254     datalink_media_t dmedia, uint32_t flags)
255 {
256 	dlmgmt_door_getnext_t	getnext;
257 	dlmgmt_getnext_retval_t	retval;
258 	uint32_t 		dlmgmt_flags;
259 	datalink_id_t		linkid = DATALINK_INVALID_LINKID;
260 	dladm_status_t		status = DLADM_STATUS_OK;
261 
262 	if (fn == NULL)
263 		return (DLADM_STATUS_BADARG);
264 
265 	dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0;
266 	dlmgmt_flags |= ((flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0);
267 
268 	getnext.ld_cmd = DLMGMT_CMD_GETNEXT;
269 	getnext.ld_class = class;
270 	getnext.ld_dmedia = dmedia;
271 	getnext.ld_flags = dlmgmt_flags;
272 
273 	do {
274 		getnext.ld_linkid = linkid;
275 		if ((status = dladm_door_call(handle, &getnext,
276 		    sizeof (getnext), &retval, sizeof (retval))) !=
277 		    DLADM_STATUS_OK) {
278 			/*
279 			 * done with walking
280 			 */
281 			break;
282 		}
283 
284 		linkid = retval.lr_linkid;
285 		if ((retval.lr_class == DATALINK_CLASS_PHYS) &&
286 		    (retval.lr_flags & DLMGMT_ACTIVE)) {
287 			/*
288 			 * An active physical link reported by the dlmgmtd
289 			 * daemon might not be active anymore. Check its
290 			 * real status.
291 			 */
292 			if (i_dladm_phys_status(handle, linkid,
293 			    &retval.lr_flags) != DLADM_STATUS_OK) {
294 				continue;
295 			}
296 
297 			if (!(dlmgmt_flags & retval.lr_flags))
298 				continue;
299 		}
300 
301 		if (fn(handle, linkid, argp) == DLADM_WALK_TERMINATE)
302 			break;
303 	} while (linkid != DATALINK_INVALID_LINKID);
304 
305 	return (status);
306 }
307 
308 /*
309  * Get the link properties structure for the given link.
310  */
311 dladm_status_t
312 dladm_read_conf(dladm_handle_t handle, datalink_id_t linkid,
313     dladm_conf_t *confp)
314 {
315 	dlmgmt_door_readconf_t		readconf;
316 	dlmgmt_readconf_retval_t	retval;
317 	dladm_status_t			status;
318 
319 	if (linkid == DATALINK_INVALID_LINKID || confp == NULL)
320 		return (DLADM_STATUS_BADARG);
321 
322 	readconf.ld_linkid = linkid;
323 	readconf.ld_cmd = DLMGMT_CMD_READCONF;
324 
325 	if ((status = dladm_door_call(handle, &readconf, sizeof (readconf),
326 	    &retval, sizeof (retval))) == DLADM_STATUS_OK) {
327 		*confp = retval.lr_conf;
328 	}
329 	return (status);
330 }
331 
332 /*
333  * Commit the given link to the data link configuration repository so
334  * that it will persist across reboots.
335  */
336 dladm_status_t
337 dladm_write_conf(dladm_handle_t handle, dladm_conf_t conf)
338 {
339 	dlmgmt_door_writeconf_t		writeconf;
340 	dlmgmt_writeconf_retval_t	retval;
341 
342 	if (conf == DLADM_INVALID_CONF)
343 		return (DLADM_STATUS_BADARG);
344 
345 	writeconf.ld_cmd = DLMGMT_CMD_WRITECONF;
346 	writeconf.ld_conf = conf;
347 
348 	return (dladm_door_call(handle, &writeconf, sizeof (writeconf), &retval,
349 	    sizeof (retval)));
350 }
351 
352 /*
353  * Given a link ID and a key, get the matching information from
354  * data link configuration repository.
355  */
356 dladm_status_t
357 dladm_get_conf_field(dladm_handle_t handle, dladm_conf_t conf, const char *attr,
358     void *attrval, size_t attrsz)
359 {
360 	dlmgmt_door_getattr_t	getattr;
361 	dlmgmt_getattr_retval_t	retval;
362 	dladm_status_t		status;
363 
364 	if (conf == DLADM_INVALID_CONF || attrval == NULL ||
365 	    attrsz == 0 || attr == NULL) {
366 		return (DLADM_STATUS_BADARG);
367 	}
368 
369 	getattr.ld_cmd = DLMGMT_CMD_GETATTR;
370 	getattr.ld_conf = conf;
371 	(void) strlcpy(getattr.ld_attr, attr, MAXLINKATTRLEN);
372 
373 	if ((status = dladm_door_call(handle, &getattr, sizeof (getattr),
374 	    &retval, sizeof (retval))) != DLADM_STATUS_OK) {
375 		return (status);
376 	}
377 
378 	if (retval.lr_attrsz > attrsz)
379 		return (DLADM_STATUS_TOOSMALL);
380 
381 	bcopy(retval.lr_attrval, attrval, retval.lr_attrsz);
382 	return (DLADM_STATUS_OK);
383 }
384 
385 /*
386  * Get next property attribute from data link configuration repository.
387  */
388 dladm_status_t
389 dladm_getnext_conf_linkprop(dladm_handle_t handle, dladm_conf_t conf,
390     const char *last_attr, char *attr, void *attrval, size_t attrsz,
391     size_t *attrszp)
392 {
393 	dlmgmt_door_linkprop_getnext_t		getnext;
394 	dlmgmt_linkprop_getnext_retval_t	retval;
395 	dladm_status_t				status;
396 
397 	if (conf == DLADM_INVALID_CONF || attrval == NULL ||
398 	    attrsz == 0 || attr == NULL) {
399 		return (DLADM_STATUS_BADARG);
400 	}
401 
402 	getnext.ld_cmd = DLMGMT_CMD_LINKPROP_GETNEXT;
403 	getnext.ld_conf = conf;
404 	(void) strlcpy(getnext.ld_last_attr, last_attr, MAXLINKATTRLEN);
405 
406 	if ((status = dladm_door_call(handle, &getnext, sizeof (getnext),
407 	    &retval, sizeof (retval))) != DLADM_STATUS_OK) {
408 		return (status);
409 	}
410 
411 	*attrszp = retval.lr_attrsz;
412 	if (retval.lr_attrsz > attrsz) {
413 		return (DLADM_STATUS_TOOSMALL);
414 	}
415 
416 	(void) strlcpy(attr, retval.lr_attr, MAXLINKATTRLEN);
417 	bcopy(retval.lr_attrval, attrval, retval.lr_attrsz);
418 	return (DLADM_STATUS_OK);
419 }
420 
421 /*
422  * Get the link ID that is associated with the given name.
423  */
424 dladm_status_t
425 dladm_name2info(dladm_handle_t handle, const char *link, datalink_id_t *linkidp,
426     uint32_t *flagp, datalink_class_t *classp, uint32_t *mediap)
427 {
428 	dlmgmt_door_getlinkid_t		getlinkid;
429 	dlmgmt_getlinkid_retval_t	retval;
430 	datalink_id_t			linkid;
431 	dladm_status_t			status;
432 
433 	getlinkid.ld_cmd = DLMGMT_CMD_GETLINKID;
434 	(void) strlcpy(getlinkid.ld_link, link, MAXLINKNAMELEN);
435 
436 	if ((status = dladm_door_call(handle, &getlinkid, sizeof (getlinkid),
437 	    &retval, sizeof (retval))) != DLADM_STATUS_OK) {
438 		return (status);
439 	}
440 
441 	linkid = retval.lr_linkid;
442 	if (retval.lr_class == DATALINK_CLASS_PHYS &&
443 	    retval.lr_flags & DLMGMT_ACTIVE) {
444 		/*
445 		 * An active physical link reported by the dlmgmtd daemon
446 		 * might not be active anymore. Check and set its real status.
447 		 */
448 		status = i_dladm_phys_status(handle, linkid, &retval.lr_flags);
449 		if (status != DLADM_STATUS_OK)
450 			return (status);
451 	}
452 
453 	if (linkidp != NULL)
454 		*linkidp = linkid;
455 	if (flagp != NULL) {
456 		*flagp = retval.lr_flags & DLMGMT_ACTIVE ? DLADM_OPT_ACTIVE : 0;
457 		*flagp |= (retval.lr_flags & DLMGMT_PERSIST) ?
458 		    DLADM_OPT_PERSIST : 0;
459 	}
460 	if (classp != NULL)
461 		*classp = retval.lr_class;
462 	if (mediap != NULL)
463 		*mediap = retval.lr_media;
464 
465 	return (DLADM_STATUS_OK);
466 }
467 
468 /*
469  * Get the link name that is associated with the given id.
470  */
471 dladm_status_t
472 dladm_datalink_id2info(dladm_handle_t handle, datalink_id_t linkid,
473     uint32_t *flagp, datalink_class_t *classp, uint32_t *mediap, char *link,
474     size_t len)
475 {
476 	dlmgmt_door_getname_t	getname;
477 	dlmgmt_getname_retval_t	retval;
478 	dladm_status_t		status;
479 
480 	if ((linkid == DATALINK_INVALID_LINKID) || (link != NULL && len == 0) ||
481 	    (link == NULL && len != 0)) {
482 		return (DLADM_STATUS_BADARG);
483 	}
484 
485 	getname.ld_cmd = DLMGMT_CMD_GETNAME;
486 	getname.ld_linkid = linkid;
487 	if ((status = dladm_door_call(handle, &getname, sizeof (getname),
488 	    &retval, sizeof (retval))) != DLADM_STATUS_OK) {
489 		return (status);
490 	}
491 
492 	if (len != 0 && (strlen(retval.lr_link) + 1 > len))
493 		return (DLADM_STATUS_TOOSMALL);
494 
495 	if (retval.lr_class == DATALINK_CLASS_PHYS &&
496 	    retval.lr_flags & DLMGMT_ACTIVE) {
497 		/*
498 		 * An active physical link reported by the dlmgmtd daemon
499 		 * might not be active anymore. Check and set its real status.
500 		 */
501 		status = i_dladm_phys_status(handle, linkid, &retval.lr_flags);
502 		if (status != DLADM_STATUS_OK)
503 			return (status);
504 	}
505 
506 	if (link != NULL)
507 		(void) strlcpy(link, retval.lr_link, len);
508 	if (classp != NULL)
509 		*classp = retval.lr_class;
510 	if (mediap != NULL)
511 		*mediap = retval.lr_media;
512 	if (flagp != NULL) {
513 		*flagp = retval.lr_flags & DLMGMT_ACTIVE ?
514 		    DLADM_OPT_ACTIVE : 0;
515 		*flagp |= (retval.lr_flags & DLMGMT_PERSIST) ?
516 		    DLADM_OPT_PERSIST : 0;
517 	}
518 	return (DLADM_STATUS_OK);
519 }
520 
521 /*
522  * Set the given attr with the given attrval for the given link.
523  */
524 dladm_status_t
525 dladm_set_conf_field(dladm_handle_t handle, dladm_conf_t conf, const char *attr,
526     dladm_datatype_t type, const void *attrval)
527 {
528 	dlmgmt_door_setattr_t	setattr;
529 	dlmgmt_setattr_retval_t	retval;
530 	size_t			attrsz;
531 
532 	if (attr == NULL || attrval == NULL)
533 		return (DLADM_STATUS_BADARG);
534 
535 	if (type == DLADM_TYPE_STR)
536 		attrsz = strlen(attrval) + 1;
537 	else
538 		attrsz = dladm_datatype_size[type];
539 
540 	if (attrsz > MAXLINKATTRVALLEN)
541 		return (DLADM_STATUS_TOOSMALL);
542 
543 	setattr.ld_cmd = DLMGMT_CMD_SETATTR;
544 	setattr.ld_conf = conf;
545 	(void) strlcpy(setattr.ld_attr, attr, MAXLINKATTRLEN);
546 	setattr.ld_attrsz = attrsz;
547 	setattr.ld_type = type;
548 	bcopy(attrval, &setattr.ld_attrval, attrsz);
549 
550 	return (dladm_door_call(handle, &setattr, sizeof (setattr), &retval,
551 	    sizeof (retval)));
552 }
553 
554 /*
555  * Unset the given attr the given link.
556  */
557 dladm_status_t
558 dladm_unset_conf_field(dladm_handle_t handle, dladm_conf_t conf,
559     const char *attr)
560 {
561 	dlmgmt_door_unsetattr_t		unsetattr;
562 	dlmgmt_unsetattr_retval_t	retval;
563 
564 	if (attr == NULL)
565 		return (DLADM_STATUS_BADARG);
566 
567 	unsetattr.ld_cmd = DLMGMT_CMD_UNSETATTR;
568 	unsetattr.ld_conf = conf;
569 	(void) strlcpy(unsetattr.ld_attr, attr, MAXLINKATTRLEN);
570 
571 	return (dladm_door_call(handle, &unsetattr, sizeof (unsetattr), &retval,
572 	    sizeof (retval)));
573 }
574 
575 /*
576  * Remove the given link ID and its entry from the data link configuration
577  * repository.
578  */
579 dladm_status_t
580 dladm_remove_conf(dladm_handle_t handle, datalink_id_t linkid)
581 {
582 	dlmgmt_door_removeconf_t	removeconf;
583 	dlmgmt_removeconf_retval_t	retval;
584 
585 	removeconf.ld_cmd = DLMGMT_CMD_REMOVECONF;
586 	removeconf.ld_linkid = linkid;
587 
588 	return (dladm_door_call(handle, &removeconf, sizeof (removeconf),
589 	    &retval, sizeof (retval)));
590 }
591 
592 /*
593  * Free the contents of the link structure.
594  */
595 void
596 dladm_destroy_conf(dladm_handle_t handle, dladm_conf_t conf)
597 {
598 	dlmgmt_door_destroyconf_t	destroyconf;
599 	dlmgmt_destroyconf_retval_t	retval;
600 
601 	if (conf == DLADM_INVALID_CONF)
602 		return;
603 
604 	destroyconf.ld_cmd = DLMGMT_CMD_DESTROYCONF;
605 	destroyconf.ld_conf = conf;
606 
607 	(void) dladm_door_call(handle, &destroyconf, sizeof (destroyconf),
608 	    &retval, sizeof (retval));
609 }
610