16197 cp/mv: add option -n
[illumos-gate.git] / usr / src / lib / libdladm / common / libdllink.c
blob5d8d39a166be881fe50106aadf848b9f0b350d7d
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
25 #include <sys/types.h>
26 #include <unistd.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <assert.h>
30 #include <ctype.h>
31 #include <strings.h>
32 #include <sys/stat.h>
33 #include <sys/dld.h>
34 #include <sys/vlan.h>
35 #include <zone.h>
36 #include <librcm.h>
37 #include <libdlpi.h>
38 #include <libdevinfo.h>
39 #include <libdlaggr.h>
40 #include <libdlvlan.h>
41 #include <libdlvnic.h>
42 #include <libdlib.h>
43 #include <libdllink.h>
44 #include <libdlmgmt.h>
45 #include <libdladm_impl.h>
46 #include <libinetutil.h>
49 * Return the attributes of the specified datalink from the DLD driver.
51 static dladm_status_t
52 i_dladm_info(dladm_handle_t handle, const datalink_id_t linkid,
53 dladm_attr_t *dap)
55 dld_ioc_attr_t dia;
57 dia.dia_linkid = linkid;
59 if (ioctl(dladm_dld_fd(handle), DLDIOC_ATTR, &dia) < 0)
60 return (dladm_errno2status(errno));
62 dap->da_max_sdu = dia.dia_max_sdu;
64 return (DLADM_STATUS_OK);
67 static dladm_status_t
68 dladm_usagelog(dladm_handle_t handle, dladm_logtype_t type,
69 dld_ioc_usagelog_t *log_info)
71 if (type == DLADM_LOGTYPE_FLOW)
72 log_info->ul_type = MAC_LOGTYPE_FLOW;
73 else
74 log_info->ul_type = MAC_LOGTYPE_LINK;
76 if (ioctl(dladm_dld_fd(handle), DLDIOC_USAGELOG, log_info) < 0)
77 return (DLADM_STATUS_IOERR);
79 return (DLADM_STATUS_OK);
82 dladm_status_t
83 dladm_start_usagelog(dladm_handle_t handle, dladm_logtype_t type,
84 uint_t interval)
86 dld_ioc_usagelog_t log_info;
88 log_info.ul_onoff = B_TRUE;
89 log_info.ul_interval = interval;
91 return (dladm_usagelog(handle, type, &log_info));
94 dladm_status_t
95 dladm_stop_usagelog(dladm_handle_t handle, dladm_logtype_t type)
97 dld_ioc_usagelog_t log_info;
99 log_info.ul_onoff = B_FALSE;
100 log_info.ul_interval = 0;
102 return (dladm_usagelog(handle, type, &log_info));
105 struct i_dladm_walk_arg {
106 dladm_walkcb_t *fn;
107 void *arg;
110 static int
111 i_dladm_walk(dladm_handle_t handle, datalink_id_t linkid, void *arg)
113 struct i_dladm_walk_arg *walk_arg = arg;
114 char link[MAXLINKNAMELEN];
116 if (dladm_datalink_id2info(handle, linkid, NULL, NULL, NULL, link,
117 sizeof (link)) == DLADM_STATUS_OK) {
118 return (walk_arg->fn(link, walk_arg->arg));
121 return (DLADM_WALK_CONTINUE);
125 * Walk all datalinks.
127 dladm_status_t
128 dladm_walk(dladm_walkcb_t *fn, dladm_handle_t handle, void *arg,
129 datalink_class_t class, datalink_media_t dmedia, uint32_t flags)
131 struct i_dladm_walk_arg walk_arg;
133 walk_arg.fn = fn;
134 walk_arg.arg = arg;
135 return (dladm_walk_datalink_id(i_dladm_walk, handle, &walk_arg,
136 class, dmedia, flags));
139 #define MAXGRPPERLINK 64
142 dladm_walk_hwgrp(dladm_handle_t handle, datalink_id_t linkid, void *arg,
143 boolean_t (*fn)(void *, dladm_hwgrp_attr_t *))
145 int bufsize, ret;
146 int nhwgrp = MAXGRPPERLINK;
147 dld_ioc_hwgrpget_t *iomp = NULL;
149 bufsize = sizeof (dld_ioc_hwgrpget_t) +
150 nhwgrp * sizeof (dld_hwgrpinfo_t);
152 if ((iomp = (dld_ioc_hwgrpget_t *)calloc(1, bufsize)) == NULL)
153 return (-1);
155 iomp->dih_size = nhwgrp * sizeof (dld_hwgrpinfo_t);
156 iomp->dih_linkid = linkid;
158 ret = ioctl(dladm_dld_fd(handle), DLDIOC_GETHWGRP, iomp);
159 if (ret == 0) {
160 uint_t i;
161 uint_t j;
162 dld_hwgrpinfo_t *dhip;
163 dladm_hwgrp_attr_t attr;
165 dhip = (dld_hwgrpinfo_t *)(iomp + 1);
166 for (i = 0; i < iomp->dih_n_groups; i++) {
167 bzero(&attr, sizeof (attr));
169 (void) strlcpy(attr.hg_link_name,
170 dhip->dhi_link_name, sizeof (attr.hg_link_name));
171 attr.hg_grp_num = dhip->dhi_grp_num;
172 attr.hg_grp_type = dhip->dhi_grp_type;
173 attr.hg_n_rings = dhip->dhi_n_rings;
174 for (j = 0; j < dhip->dhi_n_rings; j++)
175 attr.hg_rings[j] = dhip->dhi_rings[j];
176 dladm_sort_index_list(attr.hg_rings, attr.hg_n_rings);
177 attr.hg_n_clnts = dhip->dhi_n_clnts;
178 (void) strlcpy(attr.hg_client_names,
179 dhip->dhi_clnts, sizeof (attr.hg_client_names));
181 if (!(*fn)(arg, &attr))
182 break;
183 dhip++;
186 free(iomp);
187 return (ret);
191 * Invoke the specified callback for each MAC address entry defined on
192 * the specified device.
195 dladm_walk_macaddr(dladm_handle_t handle, datalink_id_t linkid, void *arg,
196 boolean_t (*fn)(void *, dladm_macaddr_attr_t *))
198 int bufsize, ret;
199 int nmacaddr = 1024;
200 dld_ioc_macaddrget_t *iomp = NULL;
202 bufsize = sizeof (dld_ioc_macaddrget_t) +
203 nmacaddr * sizeof (dld_macaddrinfo_t);
205 if ((iomp = (dld_ioc_macaddrget_t *)calloc(1, bufsize)) == NULL)
206 return (-1);
208 iomp->dig_size = nmacaddr * sizeof (dld_macaddrinfo_t);
209 iomp->dig_linkid = linkid;
211 ret = ioctl(dladm_dld_fd(handle), DLDIOC_MACADDRGET, iomp);
212 if (ret == 0) {
213 uint_t i;
214 dld_macaddrinfo_t *dmip;
215 dladm_macaddr_attr_t attr;
217 dmip = (dld_macaddrinfo_t *)(iomp + 1);
218 for (i = 0; i < iomp->dig_count; i++) {
219 bzero(&attr, sizeof (attr));
221 attr.ma_slot = dmip->dmi_slot;
222 attr.ma_flags = 0;
223 if (dmip->dmi_flags & DLDIOCMACADDR_USED)
224 attr.ma_flags |= DLADM_MACADDR_USED;
225 bcopy(dmip->dmi_addr, attr.ma_addr,
226 dmip->dmi_addrlen);
227 attr.ma_addrlen = dmip->dmi_addrlen;
228 (void) strlcpy(attr.ma_client_name,
229 dmip->dmi_client_name, MAXNAMELEN);
230 attr.ma_client_linkid = dmip->dma_client_linkid;
232 if (!(*fn)(arg, &attr))
233 break;
234 dmip++;
237 free(iomp);
238 return (ret);
242 * These routines are used by administration tools such as dladm(8) to
243 * iterate through the list of MAC interfaces
246 typedef struct dladm_mac_dev {
247 char dm_name[MAXNAMELEN];
248 struct dladm_mac_dev *dm_next;
249 } dladm_mac_dev_t;
251 typedef struct macadm_walk {
252 dladm_mac_dev_t *dmd_dev_list;
253 } dladm_mac_walk_t;
256 * Local callback invoked for each DDI_NT_NET node.
258 static int
259 i_dladm_mac_walk(di_node_t node, di_minor_t minor __unused, void *arg)
261 dladm_mac_walk_t *dmwp = arg;
262 dladm_mac_dev_t *dmdp = dmwp->dmd_dev_list;
263 dladm_mac_dev_t **last_dmdp = &dmwp->dmd_dev_list;
264 char mac[MAXNAMELEN];
266 (void) snprintf(mac, MAXNAMELEN, "%s%d",
267 di_driver_name(node), di_instance(node));
270 * Skip aggregations.
272 if (strcmp("aggr", di_driver_name(node)) == 0)
273 return (DI_WALK_CONTINUE);
276 * Skip softmacs.
278 if (strcmp("softmac", di_driver_name(node)) == 0)
279 return (DI_WALK_CONTINUE);
281 while (dmdp) {
283 * Skip duplicates.
285 if (strcmp(dmdp->dm_name, mac) == 0)
286 return (DI_WALK_CONTINUE);
288 last_dmdp = &dmdp->dm_next;
289 dmdp = dmdp->dm_next;
292 if ((dmdp = malloc(sizeof (*dmdp))) == NULL)
293 return (DI_WALK_CONTINUE);
295 (void) strlcpy(dmdp->dm_name, mac, MAXNAMELEN);
296 dmdp->dm_next = NULL;
297 *last_dmdp = dmdp;
299 return (DI_WALK_CONTINUE);
303 * Invoke the specified callback for each DDI_NT_NET node.
305 dladm_status_t
306 dladm_mac_walk(int (*fn)(const char *, void *arg), void *arg)
308 di_node_t root;
309 dladm_mac_walk_t dmw;
310 dladm_mac_dev_t *dmdp, *next;
311 boolean_t done = B_FALSE;
313 if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL)
314 return (dladm_errno2status(errno));
316 dmw.dmd_dev_list = NULL;
318 (void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, &dmw,
319 i_dladm_mac_walk);
321 di_fini(root);
323 dmdp = dmw.dmd_dev_list;
324 for (dmdp = dmw.dmd_dev_list; dmdp != NULL; dmdp = next) {
325 next = dmdp->dm_next;
326 if (!done &&
327 ((*fn)(dmdp->dm_name, arg) == DLADM_WALK_TERMINATE)) {
328 done = B_TRUE;
330 free(dmdp);
333 return (DLADM_STATUS_OK);
337 * Get the current attributes of the specified datalink.
339 dladm_status_t
340 dladm_info(dladm_handle_t handle, datalink_id_t linkid, dladm_attr_t *dap)
342 return (i_dladm_info(handle, linkid, dap));
345 const char *
346 dladm_linkstate2str(link_state_t state, char *buf)
348 const char *s;
350 switch (state) {
351 case LINK_STATE_UP:
352 s = "up";
353 break;
354 case LINK_STATE_DOWN:
355 s = "down";
356 break;
357 default:
358 s = "unknown";
359 break;
361 (void) snprintf(buf, DLADM_STRSIZE, "%s", s);
362 return (buf);
365 const char *
366 dladm_linkduplex2str(link_duplex_t duplex, char *buf)
368 const char *s;
370 switch (duplex) {
371 case LINK_DUPLEX_FULL:
372 s = "full";
373 break;
374 case LINK_DUPLEX_HALF:
375 s = "half";
376 break;
377 default:
378 s = "unknown";
379 break;
381 (void) snprintf(buf, DLADM_STRSIZE, "%s", s);
382 return (buf);
386 * Case 1: rename an existing link1 to a link2 that does not exist.
387 * Result: <linkid1, link2>
389 static dladm_status_t
390 i_dladm_rename_link_c1(dladm_handle_t handle, datalink_id_t linkid1,
391 const char *link1, const char *link2, uint32_t flags)
393 dld_ioc_rename_t dir;
394 dladm_status_t status = DLADM_STATUS_OK;
397 * Link is currently available. Check to see whether anything is
398 * holding this link to prevent a rename operation.
400 if (flags & DLADM_OPT_ACTIVE) {
401 dir.dir_linkid1 = linkid1;
402 dir.dir_linkid2 = DATALINK_INVALID_LINKID;
403 (void) strlcpy(dir.dir_link, link2, MAXLINKNAMELEN);
405 if (ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir) < 0) {
406 status = dladm_errno2status(errno);
407 return (status);
411 status = dladm_remap_datalink_id(handle, linkid1, link2);
412 if (status != DLADM_STATUS_OK && (flags & DLADM_OPT_ACTIVE)) {
413 (void) strlcpy(dir.dir_link, link1, MAXLINKNAMELEN);
414 (void) ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir);
416 return (status);
419 typedef struct link_hold_arg_s {
420 datalink_id_t linkid;
421 datalink_id_t holder;
422 uint32_t flags;
423 } link_hold_arg_t;
425 static int
426 i_dladm_aggr_link_hold(dladm_handle_t handle, datalink_id_t aggrid, void *arg)
428 link_hold_arg_t *hold_arg = arg;
429 dladm_aggr_grp_attr_t ginfo;
430 dladm_status_t status;
431 uint_t i;
433 status = dladm_aggr_info(handle, aggrid, &ginfo, hold_arg->flags);
434 if (status != DLADM_STATUS_OK)
435 return (DLADM_WALK_CONTINUE);
437 for (i = 0; i < ginfo.lg_nports; i++) {
438 if (ginfo.lg_ports[i].lp_linkid == hold_arg->linkid) {
439 hold_arg->holder = aggrid;
440 return (DLADM_WALK_TERMINATE);
443 return (DLADM_WALK_CONTINUE);
446 static int
447 i_dladm_vlan_link_hold(dladm_handle_t handle, datalink_id_t vlanid, void *arg)
449 link_hold_arg_t *hold_arg = arg;
450 dladm_vlan_attr_t vinfo;
451 dladm_status_t status;
453 status = dladm_vlan_info(handle, vlanid, &vinfo, hold_arg->flags);
454 if (status != DLADM_STATUS_OK)
455 return (DLADM_WALK_CONTINUE);
457 if (vinfo.dv_linkid == hold_arg->linkid) {
458 hold_arg->holder = vlanid;
459 return (DLADM_WALK_TERMINATE);
461 return (DLADM_WALK_CONTINUE);
465 * Case 2: rename an available physical link link1 to a REMOVED physical link
466 * link2. As a result, link1 directly inherits all datalinks configured
467 * over link2 (linkid2).
468 * Result: <linkid2, link2, link1_phymaj, link1_phyinst, link1_devname,
469 * link2_other_attr>
471 static dladm_status_t
472 i_dladm_rename_link_c2(dladm_handle_t handle, datalink_id_t linkid1,
473 datalink_id_t linkid2)
475 rcm_handle_t *rcm_hdl = NULL;
476 nvlist_t *nvl = NULL;
477 link_hold_arg_t arg;
478 dld_ioc_rename_t dir;
479 dladm_conf_t conf1, conf2;
480 char devname[MAXLINKNAMELEN];
481 uint64_t phymaj, phyinst;
482 dladm_status_t status = DLADM_STATUS_OK;
485 * First check if linkid1 is associated with any persistent
486 * aggregations or VLANs. If yes, return BUSY.
488 arg.linkid = linkid1;
489 arg.holder = DATALINK_INVALID_LINKID;
490 arg.flags = DLADM_OPT_PERSIST;
491 (void) dladm_walk_datalink_id(i_dladm_aggr_link_hold, handle, &arg,
492 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
493 if (arg.holder != DATALINK_INVALID_LINKID)
494 return (DLADM_STATUS_LINKBUSY);
496 arg.flags = DLADM_OPT_PERSIST;
497 (void) dladm_walk_datalink_id(i_dladm_vlan_link_hold, handle, &arg,
498 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
499 if (arg.holder != DATALINK_INVALID_LINKID)
500 return (DLADM_STATUS_LINKBUSY);
503 * Send DLDIOC_RENAME to request to rename link1's linkid to
504 * be linkid2. This will check whether link1 is used by any
505 * aggregations or VLANs, or is held by any application. If yes,
506 * return failure.
508 dir.dir_linkid1 = linkid1;
509 dir.dir_linkid2 = linkid2;
510 if (ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir) < 0)
511 status = dladm_errno2status(errno);
513 if (status != DLADM_STATUS_OK) {
514 return (status);
518 * Now change the phymaj, phyinst and devname associated with linkid1
519 * to be associated with linkid2. Before doing that, the old active
520 * linkprop of linkid1 should be deleted.
522 (void) dladm_set_linkprop(handle, linkid1, NULL, NULL, 0,
523 DLADM_OPT_ACTIVE);
525 if (((status = dladm_getsnap_conf(handle, linkid1, &conf1)) !=
526 DLADM_STATUS_OK) ||
527 ((status = dladm_get_conf_field(handle, conf1, FDEVNAME, devname,
528 MAXLINKNAMELEN)) != DLADM_STATUS_OK) ||
529 ((status = dladm_get_conf_field(handle, conf1, FPHYMAJ, &phymaj,
530 sizeof (uint64_t))) != DLADM_STATUS_OK) ||
531 ((status = dladm_get_conf_field(handle, conf1, FPHYINST, &phyinst,
532 sizeof (uint64_t))) != DLADM_STATUS_OK) ||
533 ((status = dladm_open_conf(handle, linkid2, &conf2)) !=
534 DLADM_STATUS_OK)) {
535 dir.dir_linkid1 = linkid2;
536 dir.dir_linkid2 = linkid1;
537 (void) dladm_init_linkprop(handle, linkid1, B_FALSE);
538 (void) ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir);
539 return (status);
542 dladm_destroy_conf(handle, conf1);
543 (void) dladm_set_conf_field(handle, conf2, FDEVNAME, DLADM_TYPE_STR,
544 devname);
545 (void) dladm_set_conf_field(handle, conf2, FPHYMAJ, DLADM_TYPE_UINT64,
546 &phymaj);
547 (void) dladm_set_conf_field(handle, conf2, FPHYINST,
548 DLADM_TYPE_UINT64, &phyinst);
549 (void) dladm_write_conf(handle, conf2);
550 dladm_destroy_conf(handle, conf2);
553 * Delete link1 and mark link2 up.
555 (void) dladm_remove_conf(handle, linkid1);
556 (void) dladm_destroy_datalink_id(handle, linkid1, DLADM_OPT_ACTIVE |
557 DLADM_OPT_PERSIST);
558 (void) dladm_up_datalink_id(handle, linkid2);
561 * Now generate the RCM_RESOURCE_LINK_NEW sysevent which can be
562 * consumed by the RCM framework to restore all the datalink and
563 * IP configuration.
565 status = DLADM_STATUS_FAILED;
566 if ((nvlist_alloc(&nvl, 0, 0) != 0) ||
567 (nvlist_add_uint64(nvl, RCM_NV_LINKID, linkid2) != 0)) {
568 goto done;
571 if (rcm_alloc_handle(NULL, 0, NULL, &rcm_hdl) != RCM_SUCCESS)
572 goto done;
574 if (rcm_notify_event(rcm_hdl, RCM_RESOURCE_LINK_NEW, 0, nvl, NULL) ==
575 RCM_SUCCESS) {
576 status = DLADM_STATUS_OK;
579 done:
580 if (rcm_hdl != NULL)
581 (void) rcm_free_handle(rcm_hdl);
582 nvlist_free(nvl);
583 return (status);
587 * case 3: rename a non-existent link to a REMOVED physical link.
588 * Set the removed physical link's device name to link1, so that
589 * when link1 attaches, it inherits all the link configuration of
590 * the removed physical link.
592 static dladm_status_t
593 i_dladm_rename_link_c3(dladm_handle_t handle, const char *link1,
594 datalink_id_t linkid2)
596 dladm_conf_t conf;
597 dladm_status_t status;
599 if (!dladm_valid_linkname(link1))
600 return (DLADM_STATUS_LINKINVAL);
602 status = dladm_open_conf(handle, linkid2, &conf);
603 if (status != DLADM_STATUS_OK)
604 goto done;
606 if ((status = dladm_set_conf_field(handle, conf, FDEVNAME,
607 DLADM_TYPE_STR, link1)) == DLADM_STATUS_OK) {
608 status = dladm_write_conf(handle, conf);
611 dladm_destroy_conf(handle, conf);
613 done:
614 return (status);
617 dladm_status_t
618 dladm_rename_link(dladm_handle_t handle, const char *link1, const char *link2)
620 datalink_id_t linkid1 = DATALINK_INVALID_LINKID;
621 datalink_id_t linkid2 = DATALINK_INVALID_LINKID;
622 uint32_t flags1, flags2;
623 datalink_class_t class1, class2;
624 uint32_t media1, media2;
625 boolean_t remphy2 = B_FALSE;
626 dladm_status_t status;
628 (void) dladm_name2info(handle, link1, &linkid1, &flags1, &class1,
629 &media1);
630 if ((dladm_name2info(handle, link2, &linkid2, &flags2, &class2,
631 &media2) == DLADM_STATUS_OK) && (class2 == DATALINK_CLASS_PHYS) &&
632 (flags2 == DLADM_OPT_PERSIST)) {
634 * see whether link2 is a removed physical link.
636 remphy2 = B_TRUE;
639 if (linkid1 != DATALINK_INVALID_LINKID) {
640 if (linkid2 == DATALINK_INVALID_LINKID) {
642 * case 1: rename an existing link to a link that
643 * does not exist.
645 status = i_dladm_rename_link_c1(handle, linkid1, link1,
646 link2, flags1);
647 } else if (remphy2) {
649 * case 2: rename an available link to a REMOVED
650 * physical link. Return failure if link1 is not
651 * an active physical link.
653 if ((class1 != class2) || (media1 != media2) ||
654 !(flags1 & DLADM_OPT_ACTIVE)) {
655 status = DLADM_STATUS_BADARG;
656 } else {
657 status = i_dladm_rename_link_c2(handle, linkid1,
658 linkid2);
660 } else {
661 status = DLADM_STATUS_EXIST;
663 } else if (remphy2) {
664 status = i_dladm_rename_link_c3(handle, link1, linkid2);
665 } else {
666 status = DLADM_STATUS_NOTFOUND;
668 return (status);
671 typedef struct consumer_del_phys_arg_s {
672 datalink_id_t linkid;
673 } consumer_del_phys_arg_t;
675 static int
676 i_dladm_vlan_link_del(dladm_handle_t handle, datalink_id_t vlanid, void *arg)
678 consumer_del_phys_arg_t *del_arg = arg;
679 dladm_vlan_attr_t vinfo;
680 dladm_status_t status;
682 status = dladm_vlan_info(handle, vlanid, &vinfo, DLADM_OPT_PERSIST);
683 if (status != DLADM_STATUS_OK)
684 return (DLADM_WALK_CONTINUE);
686 if (vinfo.dv_linkid == del_arg->linkid)
687 (void) dladm_vlan_delete(handle, vlanid, DLADM_OPT_PERSIST);
688 return (DLADM_WALK_CONTINUE);
691 static int
692 i_dladm_part_link_del(dladm_handle_t handle, datalink_id_t partid, void *arg)
694 consumer_del_phys_arg_t *del_arg = arg;
695 dladm_part_attr_t pinfo;
696 dladm_status_t status;
698 status = dladm_part_info(handle, partid, &pinfo, DLADM_OPT_PERSIST);
699 if (status != DLADM_STATUS_OK)
700 return (DLADM_WALK_CONTINUE);
702 if (pinfo.dia_physlinkid == del_arg->linkid)
703 (void) dladm_part_delete(handle, partid, DLADM_OPT_PERSIST);
704 return (DLADM_WALK_CONTINUE);
707 static int
708 i_dladm_aggr_link_del(dladm_handle_t handle, datalink_id_t aggrid, void *arg)
710 consumer_del_phys_arg_t *del_arg = arg;
711 dladm_aggr_grp_attr_t ginfo;
712 dladm_status_t status;
713 dladm_aggr_port_attr_db_t port[1];
714 uint_t i;
716 status = dladm_aggr_info(handle, aggrid, &ginfo, DLADM_OPT_PERSIST);
717 if (status != DLADM_STATUS_OK)
718 return (DLADM_WALK_CONTINUE);
720 for (i = 0; i < ginfo.lg_nports; i++)
721 if (ginfo.lg_ports[i].lp_linkid == del_arg->linkid)
722 break;
724 if (i != ginfo.lg_nports) {
725 if (ginfo.lg_nports == 1 && i == 0) {
726 consumer_del_phys_arg_t aggr_del_arg;
729 * First delete all the VLANs on this aggregation, then
730 * delete the aggregation itself.
732 aggr_del_arg.linkid = aggrid;
733 (void) dladm_walk_datalink_id(i_dladm_vlan_link_del,
734 handle, &aggr_del_arg, DATALINK_CLASS_VLAN,
735 DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
736 (void) dladm_aggr_delete(handle, aggrid,
737 DLADM_OPT_PERSIST);
738 } else {
739 port[0].lp_linkid = del_arg->linkid;
740 (void) dladm_aggr_remove(handle, aggrid, 1, port,
741 DLADM_OPT_PERSIST);
744 return (DLADM_WALK_CONTINUE);
747 typedef struct del_phys_arg_s {
748 dladm_status_t rval;
749 } del_phys_arg_t;
751 static int
752 i_dladm_phys_delete(dladm_handle_t handle, datalink_id_t linkid, void *arg)
754 uint32_t flags;
755 datalink_class_t class;
756 uint32_t media;
757 dladm_status_t status = DLADM_STATUS_OK;
758 del_phys_arg_t *del_phys_arg = arg;
759 consumer_del_phys_arg_t del_arg;
761 if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class,
762 &media, NULL, 0)) != DLADM_STATUS_OK) {
763 goto done;
767 * see whether this link is a removed physical link.
769 if ((class != DATALINK_CLASS_PHYS) || !(flags & DLADM_OPT_PERSIST) ||
770 (flags & DLADM_OPT_ACTIVE)) {
771 status = DLADM_STATUS_BADARG;
772 goto done;
775 if (media == DL_ETHER) {
776 del_arg.linkid = linkid;
777 (void) dladm_walk_datalink_id(i_dladm_aggr_link_del, handle,
778 &del_arg, DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE,
779 DLADM_OPT_PERSIST);
780 (void) dladm_walk_datalink_id(i_dladm_vlan_link_del, handle,
781 &del_arg, DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE,
782 DLADM_OPT_PERSIST);
783 } else if (media == DL_IB) {
784 del_arg.linkid = linkid;
785 (void) dladm_walk_datalink_id(i_dladm_part_link_del, handle,
786 &del_arg, DATALINK_CLASS_PART, DL_IB, DLADM_OPT_PERSIST);
789 (void) dladm_remove_conf(handle, linkid);
790 (void) dladm_destroy_datalink_id(handle, linkid, DLADM_OPT_PERSIST);
791 done:
792 del_phys_arg->rval = status;
793 return (DLADM_WALK_CONTINUE);
796 dladm_status_t
797 dladm_phys_delete(dladm_handle_t handle, datalink_id_t linkid)
799 del_phys_arg_t arg = {DLADM_STATUS_OK};
801 if (linkid == DATALINK_ALL_LINKID) {
802 (void) dladm_walk_datalink_id(i_dladm_phys_delete, handle, &arg,
803 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE,
804 DLADM_OPT_PERSIST);
805 return (DLADM_STATUS_OK);
806 } else {
807 (void) i_dladm_phys_delete(handle, linkid, &arg);
808 return (arg.rval);
812 dladm_status_t
813 dladm_phys_info(dladm_handle_t handle, datalink_id_t linkid,
814 dladm_phys_attr_t *dpap, uint32_t flags)
816 dladm_status_t status;
818 assert(flags == DLADM_OPT_ACTIVE || flags == DLADM_OPT_PERSIST);
820 switch (flags) {
821 case DLADM_OPT_PERSIST: {
822 dladm_conf_t conf;
824 status = dladm_getsnap_conf(handle, linkid, &conf);
825 if (status != DLADM_STATUS_OK)
826 return (status);
828 status = dladm_get_conf_field(handle, conf, FDEVNAME,
829 dpap->dp_dev, MAXLINKNAMELEN);
830 dladm_destroy_conf(handle, conf);
831 return (status);
833 case DLADM_OPT_ACTIVE: {
834 dld_ioc_phys_attr_t dip;
836 dip.dip_linkid = linkid;
837 if (ioctl(dladm_dld_fd(handle), DLDIOC_PHYS_ATTR, &dip) < 0) {
838 status = dladm_errno2status(errno);
839 return (status);
841 dpap->dp_novanity = dip.dip_novanity;
842 (void) strlcpy(dpap->dp_dev, dip.dip_dev, MAXLINKNAMELEN);
843 return (DLADM_STATUS_OK);
845 default:
846 return (DLADM_STATUS_BADARG);
850 typedef struct i_walk_dev_state_s {
851 const char *devname;
852 datalink_id_t linkid;
853 boolean_t found;
854 } i_walk_dev_state_t;
857 i_dladm_walk_dev2linkid(dladm_handle_t handle, datalink_id_t linkid, void *arg)
859 dladm_phys_attr_t dpa;
860 dladm_status_t status;
861 i_walk_dev_state_t *statep = arg;
863 status = dladm_phys_info(handle, linkid, &dpa, DLADM_OPT_PERSIST);
864 if ((status == DLADM_STATUS_OK) &&
865 (strcmp(statep->devname, dpa.dp_dev) == 0)) {
866 statep->found = B_TRUE;
867 statep->linkid = linkid;
868 return (DLADM_WALK_TERMINATE);
870 return (DLADM_WALK_CONTINUE);
874 * Get the linkid from the physical device name.
876 dladm_status_t
877 dladm_dev2linkid(dladm_handle_t handle, const char *devname,
878 datalink_id_t *linkidp)
880 i_walk_dev_state_t state;
882 state.found = B_FALSE;
883 state.devname = devname;
885 (void) dladm_walk_datalink_id(i_dladm_walk_dev2linkid, handle, &state,
886 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
887 if (state.found == B_TRUE) {
888 *linkidp = state.linkid;
889 return (DLADM_STATUS_OK);
890 } else {
891 return (dladm_errno2status(ENOENT));
895 static int
896 parse_devname(const char *devname, char *driver, uint_t *ppa, size_t maxlen)
898 char *cp, *tp;
899 int len;
902 * device name length must not be 0, and it must end with digit.
904 if (((len = strlen(devname)) == 0) || !isdigit(devname[len - 1]))
905 return (EINVAL);
907 (void) strlcpy(driver, devname, maxlen);
908 cp = (char *)&driver[len - 1];
910 for (tp = cp; isdigit(*tp); tp--) {
911 if (tp <= driver)
912 return (EINVAL);
915 *ppa = atoi(tp + 1);
916 *(tp + 1) = '\0';
917 return (0);
920 dladm_status_t
921 dladm_linkid2legacyname(dladm_handle_t handle, datalink_id_t linkid, char *dev,
922 size_t len)
924 char devname[MAXLINKNAMELEN];
925 uint16_t vid = VLAN_ID_NONE;
926 datalink_class_t class;
927 dladm_status_t status;
929 status = dladm_datalink_id2info(handle, linkid, NULL, &class, NULL,
930 NULL, 0);
931 if (status != DLADM_STATUS_OK)
932 goto done;
935 * If this is a VLAN, we must first determine the class and linkid of
936 * the link the VLAN has been created over.
938 if (class == DATALINK_CLASS_VLAN) {
939 dladm_vlan_attr_t dva;
941 status = dladm_vlan_info(handle, linkid, &dva,
942 DLADM_OPT_ACTIVE);
943 if (status != DLADM_STATUS_OK)
944 goto done;
945 linkid = dva.dv_linkid;
946 vid = dva.dv_vid;
948 if ((status = dladm_datalink_id2info(handle, linkid, NULL,
949 &class, NULL, NULL, 0)) != DLADM_STATUS_OK) {
950 goto done;
954 switch (class) {
955 case DATALINK_CLASS_AGGR: {
956 dladm_aggr_grp_attr_t dga;
958 status = dladm_aggr_info(handle, linkid, &dga,
959 DLADM_OPT_ACTIVE);
960 if (status != DLADM_STATUS_OK)
961 goto done;
963 if (dga.lg_key == 0) {
965 * If the key was not specified when the aggregation
966 * is created, we cannot guess its /dev node name.
968 status = DLADM_STATUS_BADARG;
969 goto done;
971 (void) snprintf(devname, MAXLINKNAMELEN, "aggr%d", dga.lg_key);
972 break;
974 case DATALINK_CLASS_PHYS: {
975 dladm_phys_attr_t dpa;
977 status = dladm_phys_info(handle, linkid, &dpa,
978 DLADM_OPT_PERSIST);
979 if (status != DLADM_STATUS_OK)
980 goto done;
982 (void) strlcpy(devname, dpa.dp_dev, MAXLINKNAMELEN);
983 break;
985 default:
986 status = DLADM_STATUS_BADARG;
987 goto done;
990 if (vid != VLAN_ID_NONE) {
991 char drv[MAXNAMELEN];
992 uint_t ppa;
993 int rv;
995 if (parse_devname(devname, drv, &ppa, MAXNAMELEN) != 0) {
996 status = DLADM_STATUS_BADARG;
997 goto done;
999 rv = snprintf(dev, len, "%s%d", drv, vid * 1000 + ppa);
1000 if (rv < 0)
1001 status = DLADM_STATUS_FAILED;
1002 else if ((size_t)rv >= len)
1003 status = DLADM_STATUS_TOOSMALL;
1004 } else {
1005 if (strlcpy(dev, devname, len) >= len)
1006 status = DLADM_STATUS_TOOSMALL;
1009 done:
1010 return (status);
1013 dladm_status_t
1014 dladm_parselink(const char *dev, char *provider, uint_t *ppa)
1016 ifspec_t ifsp;
1018 if (dev == NULL || !ifparse_ifspec(dev, &ifsp))
1019 return (DLADM_STATUS_LINKINVAL);
1021 if (provider != NULL)
1022 (void) strlcpy(provider, ifsp.ifsp_devnm, DLPI_LINKNAME_MAX);
1024 if (ppa != NULL)
1025 *ppa = ifsp.ifsp_ppa;
1027 return (DLADM_STATUS_OK);