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]
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
25 #include <sys/types.h>
38 #include <libdevinfo.h>
39 #include <libdlaggr.h>
40 #include <libdlvlan.h>
41 #include <libdlvnic.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.
52 i_dladm_info(dladm_handle_t handle
, const datalink_id_t linkid
,
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
);
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
;
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
);
83 dladm_start_usagelog(dladm_handle_t handle
, dladm_logtype_t type
,
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
));
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
{
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.
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
;
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
*))
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
)
155 iomp
->dih_size
= nhwgrp
* sizeof (dld_hwgrpinfo_t
);
156 iomp
->dih_linkid
= linkid
;
158 ret
= ioctl(dladm_dld_fd(handle
), DLDIOC_GETHWGRP
, iomp
);
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
))
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
*))
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
)
208 iomp
->dig_size
= nmacaddr
* sizeof (dld_macaddrinfo_t
);
209 iomp
->dig_linkid
= linkid
;
211 ret
= ioctl(dladm_dld_fd(handle
), DLDIOC_MACADDRGET
, iomp
);
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
;
223 if (dmip
->dmi_flags
& DLDIOCMACADDR_USED
)
224 attr
.ma_flags
|= DLADM_MACADDR_USED
;
225 bcopy(dmip
->dmi_addr
, attr
.ma_addr
,
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
))
242 * These routines are used by administration tools such as dladm(1M) 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
;
251 typedef struct macadm_walk
{
252 dladm_mac_dev_t
*dmd_dev_list
;
256 * Local callback invoked for each DDI_NT_NET node.
260 i_dladm_mac_walk(di_node_t node
, di_minor_t minor
, void *arg
)
262 dladm_mac_walk_t
*dmwp
= arg
;
263 dladm_mac_dev_t
*dmdp
= dmwp
->dmd_dev_list
;
264 dladm_mac_dev_t
**last_dmdp
= &dmwp
->dmd_dev_list
;
265 char mac
[MAXNAMELEN
];
267 (void) snprintf(mac
, MAXNAMELEN
, "%s%d",
268 di_driver_name(node
), di_instance(node
));
273 if (strcmp("aggr", di_driver_name(node
)) == 0)
274 return (DI_WALK_CONTINUE
);
279 if (strcmp("softmac", di_driver_name(node
)) == 0)
280 return (DI_WALK_CONTINUE
);
286 if (strcmp(dmdp
->dm_name
, mac
) == 0)
287 return (DI_WALK_CONTINUE
);
289 last_dmdp
= &dmdp
->dm_next
;
290 dmdp
= dmdp
->dm_next
;
293 if ((dmdp
= malloc(sizeof (*dmdp
))) == NULL
)
294 return (DI_WALK_CONTINUE
);
296 (void) strlcpy(dmdp
->dm_name
, mac
, MAXNAMELEN
);
297 dmdp
->dm_next
= NULL
;
300 return (DI_WALK_CONTINUE
);
304 * Invoke the specified callback for each DDI_NT_NET node.
307 dladm_mac_walk(int (*fn
)(const char *, void *arg
), void *arg
)
310 dladm_mac_walk_t dmw
;
311 dladm_mac_dev_t
*dmdp
, *next
;
312 boolean_t done
= B_FALSE
;
314 if ((root
= di_init("/", DINFOCACHE
)) == DI_NODE_NIL
)
315 return (dladm_errno2status(errno
));
317 dmw
.dmd_dev_list
= NULL
;
319 (void) di_walk_minor(root
, DDI_NT_NET
, DI_CHECK_ALIAS
, &dmw
,
324 dmdp
= dmw
.dmd_dev_list
;
325 for (dmdp
= dmw
.dmd_dev_list
; dmdp
!= NULL
; dmdp
= next
) {
326 next
= dmdp
->dm_next
;
328 ((*fn
)(dmdp
->dm_name
, arg
) == DLADM_WALK_TERMINATE
)) {
334 return (DLADM_STATUS_OK
);
338 * Get the current attributes of the specified datalink.
341 dladm_info(dladm_handle_t handle
, datalink_id_t linkid
, dladm_attr_t
*dap
)
343 return (i_dladm_info(handle
, linkid
, dap
));
347 dladm_linkstate2str(link_state_t state
, char *buf
)
355 case LINK_STATE_DOWN
:
362 (void) snprintf(buf
, DLADM_STRSIZE
, "%s", s
);
367 dladm_linkduplex2str(link_duplex_t duplex
, char *buf
)
372 case LINK_DUPLEX_FULL
:
375 case LINK_DUPLEX_HALF
:
382 (void) snprintf(buf
, DLADM_STRSIZE
, "%s", s
);
387 * Case 1: rename an existing link1 to a link2 that does not exist.
388 * Result: <linkid1, link2>
390 static dladm_status_t
391 i_dladm_rename_link_c1(dladm_handle_t handle
, datalink_id_t linkid1
,
392 const char *link1
, const char *link2
, uint32_t flags
)
394 dld_ioc_rename_t dir
;
395 dladm_status_t status
= DLADM_STATUS_OK
;
398 * Link is currently available. Check to see whether anything is
399 * holding this link to prevent a rename operation.
401 if (flags
& DLADM_OPT_ACTIVE
) {
402 dir
.dir_linkid1
= linkid1
;
403 dir
.dir_linkid2
= DATALINK_INVALID_LINKID
;
404 (void) strlcpy(dir
.dir_link
, link2
, MAXLINKNAMELEN
);
406 if (ioctl(dladm_dld_fd(handle
), DLDIOC_RENAME
, &dir
) < 0) {
407 status
= dladm_errno2status(errno
);
412 status
= dladm_remap_datalink_id(handle
, linkid1
, link2
);
413 if (status
!= DLADM_STATUS_OK
&& (flags
& DLADM_OPT_ACTIVE
)) {
414 (void) strlcpy(dir
.dir_link
, link1
, MAXLINKNAMELEN
);
415 (void) ioctl(dladm_dld_fd(handle
), DLDIOC_RENAME
, &dir
);
420 typedef struct link_hold_arg_s
{
421 datalink_id_t linkid
;
422 datalink_id_t holder
;
427 i_dladm_aggr_link_hold(dladm_handle_t handle
, datalink_id_t aggrid
, void *arg
)
429 link_hold_arg_t
*hold_arg
= arg
;
430 dladm_aggr_grp_attr_t ginfo
;
431 dladm_status_t status
;
434 status
= dladm_aggr_info(handle
, aggrid
, &ginfo
, hold_arg
->flags
);
435 if (status
!= DLADM_STATUS_OK
)
436 return (DLADM_WALK_CONTINUE
);
438 for (i
= 0; i
< ginfo
.lg_nports
; i
++) {
439 if (ginfo
.lg_ports
[i
].lp_linkid
== hold_arg
->linkid
) {
440 hold_arg
->holder
= aggrid
;
441 return (DLADM_WALK_TERMINATE
);
444 return (DLADM_WALK_CONTINUE
);
448 i_dladm_vlan_link_hold(dladm_handle_t handle
, datalink_id_t vlanid
, void *arg
)
450 link_hold_arg_t
*hold_arg
= arg
;
451 dladm_vlan_attr_t vinfo
;
452 dladm_status_t status
;
454 status
= dladm_vlan_info(handle
, vlanid
, &vinfo
, hold_arg
->flags
);
455 if (status
!= DLADM_STATUS_OK
)
456 return (DLADM_WALK_CONTINUE
);
458 if (vinfo
.dv_linkid
== hold_arg
->linkid
) {
459 hold_arg
->holder
= vlanid
;
460 return (DLADM_WALK_TERMINATE
);
462 return (DLADM_WALK_CONTINUE
);
466 * Case 2: rename an available physical link link1 to a REMOVED physical link
467 * link2. As a result, link1 directly inherits all datalinks configured
468 * over link2 (linkid2).
469 * Result: <linkid2, link2, link1_phymaj, link1_phyinst, link1_devname,
472 static dladm_status_t
473 i_dladm_rename_link_c2(dladm_handle_t handle
, datalink_id_t linkid1
,
474 datalink_id_t linkid2
)
476 rcm_handle_t
*rcm_hdl
= NULL
;
477 nvlist_t
*nvl
= NULL
;
479 dld_ioc_rename_t dir
;
480 dladm_conf_t conf1
, conf2
;
481 char devname
[MAXLINKNAMELEN
];
482 uint64_t phymaj
, phyinst
;
483 dladm_status_t status
= DLADM_STATUS_OK
;
486 * First check if linkid1 is associated with any persistent
487 * aggregations or VLANs. If yes, return BUSY.
489 arg
.linkid
= linkid1
;
490 arg
.holder
= DATALINK_INVALID_LINKID
;
491 arg
.flags
= DLADM_OPT_PERSIST
;
492 (void) dladm_walk_datalink_id(i_dladm_aggr_link_hold
, handle
, &arg
,
493 DATALINK_CLASS_AGGR
, DATALINK_ANY_MEDIATYPE
, DLADM_OPT_PERSIST
);
494 if (arg
.holder
!= DATALINK_INVALID_LINKID
)
495 return (DLADM_STATUS_LINKBUSY
);
497 arg
.flags
= DLADM_OPT_PERSIST
;
498 (void) dladm_walk_datalink_id(i_dladm_vlan_link_hold
, handle
, &arg
,
499 DATALINK_CLASS_VLAN
, DATALINK_ANY_MEDIATYPE
, DLADM_OPT_PERSIST
);
500 if (arg
.holder
!= DATALINK_INVALID_LINKID
)
501 return (DLADM_STATUS_LINKBUSY
);
504 * Send DLDIOC_RENAME to request to rename link1's linkid to
505 * be linkid2. This will check whether link1 is used by any
506 * aggregations or VLANs, or is held by any application. If yes,
509 dir
.dir_linkid1
= linkid1
;
510 dir
.dir_linkid2
= linkid2
;
511 if (ioctl(dladm_dld_fd(handle
), DLDIOC_RENAME
, &dir
) < 0)
512 status
= dladm_errno2status(errno
);
514 if (status
!= DLADM_STATUS_OK
) {
519 * Now change the phymaj, phyinst and devname associated with linkid1
520 * to be associated with linkid2. Before doing that, the old active
521 * linkprop of linkid1 should be deleted.
523 (void) dladm_set_linkprop(handle
, linkid1
, NULL
, NULL
, 0,
526 if (((status
= dladm_getsnap_conf(handle
, linkid1
, &conf1
)) !=
528 ((status
= dladm_get_conf_field(handle
, conf1
, FDEVNAME
, devname
,
529 MAXLINKNAMELEN
)) != DLADM_STATUS_OK
) ||
530 ((status
= dladm_get_conf_field(handle
, conf1
, FPHYMAJ
, &phymaj
,
531 sizeof (uint64_t))) != DLADM_STATUS_OK
) ||
532 ((status
= dladm_get_conf_field(handle
, conf1
, FPHYINST
, &phyinst
,
533 sizeof (uint64_t))) != DLADM_STATUS_OK
) ||
534 ((status
= dladm_open_conf(handle
, linkid2
, &conf2
)) !=
536 dir
.dir_linkid1
= linkid2
;
537 dir
.dir_linkid2
= linkid1
;
538 (void) dladm_init_linkprop(handle
, linkid1
, B_FALSE
);
539 (void) ioctl(dladm_dld_fd(handle
), DLDIOC_RENAME
, &dir
);
543 dladm_destroy_conf(handle
, conf1
);
544 (void) dladm_set_conf_field(handle
, conf2
, FDEVNAME
, DLADM_TYPE_STR
,
546 (void) dladm_set_conf_field(handle
, conf2
, FPHYMAJ
, DLADM_TYPE_UINT64
,
548 (void) dladm_set_conf_field(handle
, conf2
, FPHYINST
,
549 DLADM_TYPE_UINT64
, &phyinst
);
550 (void) dladm_write_conf(handle
, conf2
);
551 dladm_destroy_conf(handle
, conf2
);
554 * Delete link1 and mark link2 up.
556 (void) dladm_remove_conf(handle
, linkid1
);
557 (void) dladm_destroy_datalink_id(handle
, linkid1
, DLADM_OPT_ACTIVE
|
559 (void) dladm_up_datalink_id(handle
, linkid2
);
562 * Now generate the RCM_RESOURCE_LINK_NEW sysevent which can be
563 * consumed by the RCM framework to restore all the datalink and
566 status
= DLADM_STATUS_FAILED
;
567 if ((nvlist_alloc(&nvl
, 0, 0) != 0) ||
568 (nvlist_add_uint64(nvl
, RCM_NV_LINKID
, linkid2
) != 0)) {
572 if (rcm_alloc_handle(NULL
, 0, NULL
, &rcm_hdl
) != RCM_SUCCESS
)
575 if (rcm_notify_event(rcm_hdl
, RCM_RESOURCE_LINK_NEW
, 0, nvl
, NULL
) ==
577 status
= DLADM_STATUS_OK
;
582 (void) rcm_free_handle(rcm_hdl
);
588 * case 3: rename a non-existent link to a REMOVED physical link.
589 * Set the removed physical link's device name to link1, so that
590 * when link1 attaches, it inherits all the link configuration of
591 * the removed physical link.
593 static dladm_status_t
594 i_dladm_rename_link_c3(dladm_handle_t handle
, const char *link1
,
595 datalink_id_t linkid2
)
598 dladm_status_t status
;
600 if (!dladm_valid_linkname(link1
))
601 return (DLADM_STATUS_LINKINVAL
);
603 status
= dladm_open_conf(handle
, linkid2
, &conf
);
604 if (status
!= DLADM_STATUS_OK
)
607 if ((status
= dladm_set_conf_field(handle
, conf
, FDEVNAME
,
608 DLADM_TYPE_STR
, link1
)) == DLADM_STATUS_OK
) {
609 status
= dladm_write_conf(handle
, conf
);
612 dladm_destroy_conf(handle
, conf
);
619 dladm_rename_link(dladm_handle_t handle
, const char *link1
, const char *link2
)
621 datalink_id_t linkid1
= DATALINK_INVALID_LINKID
;
622 datalink_id_t linkid2
= DATALINK_INVALID_LINKID
;
623 uint32_t flags1
, flags2
;
624 datalink_class_t class1
, class2
;
625 uint32_t media1
, media2
;
626 boolean_t remphy2
= B_FALSE
;
627 dladm_status_t status
;
629 (void) dladm_name2info(handle
, link1
, &linkid1
, &flags1
, &class1
,
631 if ((dladm_name2info(handle
, link2
, &linkid2
, &flags2
, &class2
,
632 &media2
) == DLADM_STATUS_OK
) && (class2
== DATALINK_CLASS_PHYS
) &&
633 (flags2
== DLADM_OPT_PERSIST
)) {
635 * see whether link2 is a removed physical link.
640 if (linkid1
!= DATALINK_INVALID_LINKID
) {
641 if (linkid2
== DATALINK_INVALID_LINKID
) {
643 * case 1: rename an existing link to a link that
646 status
= i_dladm_rename_link_c1(handle
, linkid1
, link1
,
648 } else if (remphy2
) {
650 * case 2: rename an available link to a REMOVED
651 * physical link. Return failure if link1 is not
652 * an active physical link.
654 if ((class1
!= class2
) || (media1
!= media2
) ||
655 !(flags1
& DLADM_OPT_ACTIVE
)) {
656 status
= DLADM_STATUS_BADARG
;
658 status
= i_dladm_rename_link_c2(handle
, linkid1
,
662 status
= DLADM_STATUS_EXIST
;
664 } else if (remphy2
) {
665 status
= i_dladm_rename_link_c3(handle
, link1
, linkid2
);
667 status
= DLADM_STATUS_NOTFOUND
;
672 typedef struct consumer_del_phys_arg_s
{
673 datalink_id_t linkid
;
674 } consumer_del_phys_arg_t
;
677 i_dladm_vlan_link_del(dladm_handle_t handle
, datalink_id_t vlanid
, void *arg
)
679 consumer_del_phys_arg_t
*del_arg
= arg
;
680 dladm_vlan_attr_t vinfo
;
681 dladm_status_t status
;
683 status
= dladm_vlan_info(handle
, vlanid
, &vinfo
, DLADM_OPT_PERSIST
);
684 if (status
!= DLADM_STATUS_OK
)
685 return (DLADM_WALK_CONTINUE
);
687 if (vinfo
.dv_linkid
== del_arg
->linkid
)
688 (void) dladm_vlan_delete(handle
, vlanid
, DLADM_OPT_PERSIST
);
689 return (DLADM_WALK_CONTINUE
);
693 i_dladm_part_link_del(dladm_handle_t handle
, datalink_id_t partid
, void *arg
)
695 consumer_del_phys_arg_t
*del_arg
= arg
;
696 dladm_part_attr_t pinfo
;
697 dladm_status_t status
;
699 status
= dladm_part_info(handle
, partid
, &pinfo
, DLADM_OPT_PERSIST
);
700 if (status
!= DLADM_STATUS_OK
)
701 return (DLADM_WALK_CONTINUE
);
703 if (pinfo
.dia_physlinkid
== del_arg
->linkid
)
704 (void) dladm_part_delete(handle
, partid
, DLADM_OPT_PERSIST
);
705 return (DLADM_WALK_CONTINUE
);
709 i_dladm_aggr_link_del(dladm_handle_t handle
, datalink_id_t aggrid
, void *arg
)
711 consumer_del_phys_arg_t
*del_arg
= arg
;
712 dladm_aggr_grp_attr_t ginfo
;
713 dladm_status_t status
;
714 dladm_aggr_port_attr_db_t port
[1];
717 status
= dladm_aggr_info(handle
, aggrid
, &ginfo
, DLADM_OPT_PERSIST
);
718 if (status
!= DLADM_STATUS_OK
)
719 return (DLADM_WALK_CONTINUE
);
721 for (i
= 0; i
< ginfo
.lg_nports
; i
++)
722 if (ginfo
.lg_ports
[i
].lp_linkid
== del_arg
->linkid
)
725 if (i
!= ginfo
.lg_nports
) {
726 if (ginfo
.lg_nports
== 1 && i
== 0) {
727 consumer_del_phys_arg_t aggr_del_arg
;
730 * First delete all the VLANs on this aggregation, then
731 * delete the aggregation itself.
733 aggr_del_arg
.linkid
= aggrid
;
734 (void) dladm_walk_datalink_id(i_dladm_vlan_link_del
,
735 handle
, &aggr_del_arg
, DATALINK_CLASS_VLAN
,
736 DATALINK_ANY_MEDIATYPE
, DLADM_OPT_PERSIST
);
737 (void) dladm_aggr_delete(handle
, aggrid
,
740 port
[0].lp_linkid
= del_arg
->linkid
;
741 (void) dladm_aggr_remove(handle
, aggrid
, 1, port
,
745 return (DLADM_WALK_CONTINUE
);
748 typedef struct del_phys_arg_s
{
753 i_dladm_phys_delete(dladm_handle_t handle
, datalink_id_t linkid
, void *arg
)
756 datalink_class_t
class;
758 dladm_status_t status
= DLADM_STATUS_OK
;
759 del_phys_arg_t
*del_phys_arg
= arg
;
760 consumer_del_phys_arg_t del_arg
;
762 if ((status
= dladm_datalink_id2info(handle
, linkid
, &flags
, &class,
763 &media
, NULL
, 0)) != DLADM_STATUS_OK
) {
768 * see whether this link is a removed physical link.
770 if ((class != DATALINK_CLASS_PHYS
) || !(flags
& DLADM_OPT_PERSIST
) ||
771 (flags
& DLADM_OPT_ACTIVE
)) {
772 status
= DLADM_STATUS_BADARG
;
776 if (media
== DL_ETHER
) {
777 del_arg
.linkid
= linkid
;
778 (void) dladm_walk_datalink_id(i_dladm_aggr_link_del
, handle
,
779 &del_arg
, DATALINK_CLASS_AGGR
, DATALINK_ANY_MEDIATYPE
,
781 (void) dladm_walk_datalink_id(i_dladm_vlan_link_del
, handle
,
782 &del_arg
, DATALINK_CLASS_VLAN
, DATALINK_ANY_MEDIATYPE
,
784 } else if (media
== DL_IB
) {
785 del_arg
.linkid
= linkid
;
786 (void) dladm_walk_datalink_id(i_dladm_part_link_del
, handle
,
787 &del_arg
, DATALINK_CLASS_PART
, DL_IB
, DLADM_OPT_PERSIST
);
790 (void) dladm_remove_conf(handle
, linkid
);
791 (void) dladm_destroy_datalink_id(handle
, linkid
, DLADM_OPT_PERSIST
);
793 del_phys_arg
->rval
= status
;
794 return (DLADM_WALK_CONTINUE
);
798 dladm_phys_delete(dladm_handle_t handle
, datalink_id_t linkid
)
800 del_phys_arg_t arg
= {DLADM_STATUS_OK
};
802 if (linkid
== DATALINK_ALL_LINKID
) {
803 (void) dladm_walk_datalink_id(i_dladm_phys_delete
, handle
, &arg
,
804 DATALINK_CLASS_PHYS
, DATALINK_ANY_MEDIATYPE
,
806 return (DLADM_STATUS_OK
);
808 (void) i_dladm_phys_delete(handle
, linkid
, &arg
);
814 dladm_phys_info(dladm_handle_t handle
, datalink_id_t linkid
,
815 dladm_phys_attr_t
*dpap
, uint32_t flags
)
817 dladm_status_t status
;
819 assert(flags
== DLADM_OPT_ACTIVE
|| flags
== DLADM_OPT_PERSIST
);
822 case DLADM_OPT_PERSIST
: {
825 status
= dladm_getsnap_conf(handle
, linkid
, &conf
);
826 if (status
!= DLADM_STATUS_OK
)
829 status
= dladm_get_conf_field(handle
, conf
, FDEVNAME
,
830 dpap
->dp_dev
, MAXLINKNAMELEN
);
831 dladm_destroy_conf(handle
, conf
);
834 case DLADM_OPT_ACTIVE
: {
835 dld_ioc_phys_attr_t dip
;
837 dip
.dip_linkid
= linkid
;
838 if (ioctl(dladm_dld_fd(handle
), DLDIOC_PHYS_ATTR
, &dip
) < 0) {
839 status
= dladm_errno2status(errno
);
842 dpap
->dp_novanity
= dip
.dip_novanity
;
843 (void) strlcpy(dpap
->dp_dev
, dip
.dip_dev
, MAXLINKNAMELEN
);
844 return (DLADM_STATUS_OK
);
847 return (DLADM_STATUS_BADARG
);
851 typedef struct i_walk_dev_state_s
{
853 datalink_id_t linkid
;
855 } i_walk_dev_state_t
;
858 i_dladm_walk_dev2linkid(dladm_handle_t handle
, datalink_id_t linkid
, void *arg
)
860 dladm_phys_attr_t dpa
;
861 dladm_status_t status
;
862 i_walk_dev_state_t
*statep
= arg
;
864 status
= dladm_phys_info(handle
, linkid
, &dpa
, DLADM_OPT_PERSIST
);
865 if ((status
== DLADM_STATUS_OK
) &&
866 (strcmp(statep
->devname
, dpa
.dp_dev
) == 0)) {
867 statep
->found
= B_TRUE
;
868 statep
->linkid
= linkid
;
869 return (DLADM_WALK_TERMINATE
);
871 return (DLADM_WALK_CONTINUE
);
875 * Get the linkid from the physical device name.
878 dladm_dev2linkid(dladm_handle_t handle
, const char *devname
,
879 datalink_id_t
*linkidp
)
881 i_walk_dev_state_t state
;
883 state
.found
= B_FALSE
;
884 state
.devname
= devname
;
886 (void) dladm_walk_datalink_id(i_dladm_walk_dev2linkid
, handle
, &state
,
887 DATALINK_CLASS_PHYS
, DATALINK_ANY_MEDIATYPE
, DLADM_OPT_PERSIST
);
888 if (state
.found
== B_TRUE
) {
889 *linkidp
= state
.linkid
;
890 return (DLADM_STATUS_OK
);
892 return (dladm_errno2status(ENOENT
));
897 parse_devname(const char *devname
, char *driver
, uint_t
*ppa
, size_t maxlen
)
903 * device name length must not be 0, and it must end with digit.
905 if (((len
= strlen(devname
)) == 0) || !isdigit(devname
[len
- 1]))
908 (void) strlcpy(driver
, devname
, maxlen
);
909 cp
= (char *)&driver
[len
- 1];
911 for (tp
= cp
; isdigit(*tp
); tp
--) {
922 dladm_linkid2legacyname(dladm_handle_t handle
, datalink_id_t linkid
, char *dev
,
925 char devname
[MAXLINKNAMELEN
];
926 uint16_t vid
= VLAN_ID_NONE
;
927 datalink_class_t
class;
928 dladm_status_t status
;
930 status
= dladm_datalink_id2info(handle
, linkid
, NULL
, &class, NULL
,
932 if (status
!= DLADM_STATUS_OK
)
936 * If this is a VLAN, we must first determine the class and linkid of
937 * the link the VLAN has been created over.
939 if (class == DATALINK_CLASS_VLAN
) {
940 dladm_vlan_attr_t dva
;
942 status
= dladm_vlan_info(handle
, linkid
, &dva
,
944 if (status
!= DLADM_STATUS_OK
)
946 linkid
= dva
.dv_linkid
;
949 if ((status
= dladm_datalink_id2info(handle
, linkid
, NULL
,
950 &class, NULL
, NULL
, 0)) != DLADM_STATUS_OK
) {
956 case DATALINK_CLASS_AGGR
: {
957 dladm_aggr_grp_attr_t dga
;
959 status
= dladm_aggr_info(handle
, linkid
, &dga
,
961 if (status
!= DLADM_STATUS_OK
)
964 if (dga
.lg_key
== 0) {
966 * If the key was not specified when the aggregation
967 * is created, we cannot guess its /dev node name.
969 status
= DLADM_STATUS_BADARG
;
972 (void) snprintf(devname
, MAXLINKNAMELEN
, "aggr%d", dga
.lg_key
);
975 case DATALINK_CLASS_PHYS
: {
976 dladm_phys_attr_t dpa
;
978 status
= dladm_phys_info(handle
, linkid
, &dpa
,
980 if (status
!= DLADM_STATUS_OK
)
983 (void) strlcpy(devname
, dpa
.dp_dev
, MAXLINKNAMELEN
);
987 status
= DLADM_STATUS_BADARG
;
991 if (vid
!= VLAN_ID_NONE
) {
992 char drv
[MAXNAMELEN
];
995 if (parse_devname(devname
, drv
, &ppa
, MAXNAMELEN
) != 0) {
996 status
= DLADM_STATUS_BADARG
;
999 if (snprintf(dev
, len
, "%s%d", drv
, vid
* 1000 + ppa
) >= len
)
1000 status
= DLADM_STATUS_TOOSMALL
;
1002 if (strlcpy(dev
, devname
, len
) >= len
)
1003 status
= DLADM_STATUS_TOOSMALL
;
1011 dladm_parselink(const char *dev
, char *provider
, uint_t
*ppa
)
1015 if (dev
== NULL
|| !ifparse_ifspec(dev
, &ifsp
))
1016 return (DLADM_STATUS_LINKINVAL
);
1018 if (provider
!= NULL
)
1019 (void) strlcpy(provider
, ifsp
.ifsp_devnm
, DLPI_LINKNAME_MAX
);
1022 *ppa
= ifsp
.ifsp_ppa
;
1024 return (DLADM_STATUS_OK
);