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