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
dladm_door_call(dladm_handle_t handle,void * arg,size_t asize,void * rbuf,size_t * rsizep)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
dladm_create_datalink_id(dladm_handle_t handle,const char * link,datalink_class_t class,uint32_t media,uint32_t flags,datalink_id_t * linkidp)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
dladm_destroy_datalink_id(dladm_handle_t handle,datalink_id_t linkid,uint32_t flags)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
dladm_remap_datalink_id(dladm_handle_t handle,datalink_id_t linkid,const char * link)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
dladm_up_datalink_id(dladm_handle_t handle,datalink_id_t linkid)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
dladm_create_conf(dladm_handle_t handle,const char * link,datalink_id_t linkid,datalink_class_t class,uint32_t media,dladm_conf_t * confp)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
i_dladm_phys_status(dladm_handle_t handle,datalink_id_t linkid,uint32_t * flagsp)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
dladm_walk_datalink_id(int (* fn)(dladm_handle_t,datalink_id_t,void *),dladm_handle_t handle,void * argp,datalink_class_t class,datalink_media_t dmedia,uint32_t flags)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
dladm_open_conf(dladm_handle_t handle,datalink_id_t linkid,dladm_conf_t * confp)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
dladm_getsnap_conf(dladm_handle_t handle,datalink_id_t linkid,dladm_conf_t * confp)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
dladm_write_conf(dladm_handle_t handle,dladm_conf_t conf)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
dladm_get_conf_field(dladm_handle_t handle,dladm_conf_t conf,const char * attr,void * attrval,size_t attrsz)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
dladm_getnext_conf_linkprop(dladm_handle_t handle __unused,dladm_conf_t conf,const char * last_attr,char * attr,void * attrval,size_t attrsz,size_t * attrszp)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
dladm_name2info(dladm_handle_t handle,const char * link,datalink_id_t * linkidp,uint32_t * flagp,datalink_class_t * classp,uint32_t * mediap)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
dladm_datalink_id2info(dladm_handle_t handle,datalink_id_t linkid,uint32_t * flagp,datalink_class_t * classp,uint32_t * mediap,char * link,size_t len)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
dladm_set_conf_field(dladm_handle_t handle,dladm_conf_t conf,const char * attr,dladm_datatype_t type,const void * attrval)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
dladm_unset_conf_field(dladm_handle_t handle,dladm_conf_t conf,const char * attr)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
dladm_remove_conf(dladm_handle_t handle,datalink_id_t linkid)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
dladm_destroy_conf(dladm_handle_t handle,dladm_conf_t conf)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
dladm_zone_boot(dladm_handle_t handle,zoneid_t zoneid)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
dladm_zone_halt(dladm_handle_t handle,zoneid_t zoneid)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