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(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
;
251 typedef struct macadm_walk
{
252 dladm_mac_dev_t
*dmd_dev_list
;
256 * Local callback invoked for each DDI_NT_NET node.
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
));
272 if (strcmp("aggr", di_driver_name(node
)) == 0)
273 return (DI_WALK_CONTINUE
);
278 if (strcmp("softmac", di_driver_name(node
)) == 0)
279 return (DI_WALK_CONTINUE
);
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
;
299 return (DI_WALK_CONTINUE
);
303 * Invoke the specified callback for each DDI_NT_NET node.
306 dladm_mac_walk(int (*fn
)(const char *, void *arg
), void *arg
)
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
,
323 dmdp
= dmw
.dmd_dev_list
;
324 for (dmdp
= dmw
.dmd_dev_list
; dmdp
!= NULL
; dmdp
= next
) {
325 next
= dmdp
->dm_next
;
327 ((*fn
)(dmdp
->dm_name
, arg
) == DLADM_WALK_TERMINATE
)) {
333 return (DLADM_STATUS_OK
);
337 * Get the current attributes of the specified datalink.
340 dladm_info(dladm_handle_t handle
, datalink_id_t linkid
, dladm_attr_t
*dap
)
342 return (i_dladm_info(handle
, linkid
, dap
));
346 dladm_linkstate2str(link_state_t state
, char *buf
)
354 case LINK_STATE_DOWN
:
361 (void) snprintf(buf
, DLADM_STRSIZE
, "%s", s
);
366 dladm_linkduplex2str(link_duplex_t duplex
, char *buf
)
371 case LINK_DUPLEX_FULL
:
374 case LINK_DUPLEX_HALF
:
381 (void) snprintf(buf
, DLADM_STRSIZE
, "%s", s
);
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
);
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
);
419 typedef struct link_hold_arg_s
{
420 datalink_id_t linkid
;
421 datalink_id_t holder
;
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
;
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
);
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,
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
;
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,
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
) {
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,
525 if (((status
= dladm_getsnap_conf(handle
, linkid1
, &conf1
)) !=
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
)) !=
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
);
542 dladm_destroy_conf(handle
, conf1
);
543 (void) dladm_set_conf_field(handle
, conf2
, FDEVNAME
, DLADM_TYPE_STR
,
545 (void) dladm_set_conf_field(handle
, conf2
, FPHYMAJ
, DLADM_TYPE_UINT64
,
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
|
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
565 status
= DLADM_STATUS_FAILED
;
566 if ((nvlist_alloc(&nvl
, 0, 0) != 0) ||
567 (nvlist_add_uint64(nvl
, RCM_NV_LINKID
, linkid2
) != 0)) {
571 if (rcm_alloc_handle(NULL
, 0, NULL
, &rcm_hdl
) != RCM_SUCCESS
)
574 if (rcm_notify_event(rcm_hdl
, RCM_RESOURCE_LINK_NEW
, 0, nvl
, NULL
) ==
576 status
= DLADM_STATUS_OK
;
581 (void) rcm_free_handle(rcm_hdl
);
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
)
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
)
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
);
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
,
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.
639 if (linkid1
!= DATALINK_INVALID_LINKID
) {
640 if (linkid2
== DATALINK_INVALID_LINKID
) {
642 * case 1: rename an existing link to a link that
645 status
= i_dladm_rename_link_c1(handle
, linkid1
, link1
,
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
;
657 status
= i_dladm_rename_link_c2(handle
, linkid1
,
661 status
= DLADM_STATUS_EXIST
;
663 } else if (remphy2
) {
664 status
= i_dladm_rename_link_c3(handle
, link1
, linkid2
);
666 status
= DLADM_STATUS_NOTFOUND
;
671 typedef struct consumer_del_phys_arg_s
{
672 datalink_id_t linkid
;
673 } consumer_del_phys_arg_t
;
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
);
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
);
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];
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
)
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
,
739 port
[0].lp_linkid
= del_arg
->linkid
;
740 (void) dladm_aggr_remove(handle
, aggrid
, 1, port
,
744 return (DLADM_WALK_CONTINUE
);
747 typedef struct del_phys_arg_s
{
752 i_dladm_phys_delete(dladm_handle_t handle
, datalink_id_t linkid
, void *arg
)
755 datalink_class_t
class;
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
) {
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
;
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
,
780 (void) dladm_walk_datalink_id(i_dladm_vlan_link_del
, handle
,
781 &del_arg
, DATALINK_CLASS_VLAN
, DATALINK_ANY_MEDIATYPE
,
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
);
792 del_phys_arg
->rval
= status
;
793 return (DLADM_WALK_CONTINUE
);
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
,
805 return (DLADM_STATUS_OK
);
807 (void) i_dladm_phys_delete(handle
, linkid
, &arg
);
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
);
821 case DLADM_OPT_PERSIST
: {
824 status
= dladm_getsnap_conf(handle
, linkid
, &conf
);
825 if (status
!= DLADM_STATUS_OK
)
828 status
= dladm_get_conf_field(handle
, conf
, FDEVNAME
,
829 dpap
->dp_dev
, MAXLINKNAMELEN
);
830 dladm_destroy_conf(handle
, conf
);
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
);
841 dpap
->dp_novanity
= dip
.dip_novanity
;
842 (void) strlcpy(dpap
->dp_dev
, dip
.dip_dev
, MAXLINKNAMELEN
);
843 return (DLADM_STATUS_OK
);
846 return (DLADM_STATUS_BADARG
);
850 typedef struct i_walk_dev_state_s
{
852 datalink_id_t linkid
;
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.
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
);
891 return (dladm_errno2status(ENOENT
));
896 parse_devname(const char *devname
, char *driver
, uint_t
*ppa
, size_t maxlen
)
902 * device name length must not be 0, and it must end with digit.
904 if (((len
= strlen(devname
)) == 0) || !isdigit(devname
[len
- 1]))
907 (void) strlcpy(driver
, devname
, maxlen
);
908 cp
= (char *)&driver
[len
- 1];
910 for (tp
= cp
; isdigit(*tp
); tp
--) {
921 dladm_linkid2legacyname(dladm_handle_t handle
, datalink_id_t linkid
, char *dev
,
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
,
931 if (status
!= DLADM_STATUS_OK
)
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
,
943 if (status
!= DLADM_STATUS_OK
)
945 linkid
= dva
.dv_linkid
;
948 if ((status
= dladm_datalink_id2info(handle
, linkid
, NULL
,
949 &class, NULL
, NULL
, 0)) != DLADM_STATUS_OK
) {
955 case DATALINK_CLASS_AGGR
: {
956 dladm_aggr_grp_attr_t dga
;
958 status
= dladm_aggr_info(handle
, linkid
, &dga
,
960 if (status
!= DLADM_STATUS_OK
)
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
;
971 (void) snprintf(devname
, MAXLINKNAMELEN
, "aggr%d", dga
.lg_key
);
974 case DATALINK_CLASS_PHYS
: {
975 dladm_phys_attr_t dpa
;
977 status
= dladm_phys_info(handle
, linkid
, &dpa
,
979 if (status
!= DLADM_STATUS_OK
)
982 (void) strlcpy(devname
, dpa
.dp_dev
, MAXLINKNAMELEN
);
986 status
= DLADM_STATUS_BADARG
;
990 if (vid
!= VLAN_ID_NONE
) {
991 char drv
[MAXNAMELEN
];
995 if (parse_devname(devname
, drv
, &ppa
, MAXNAMELEN
) != 0) {
996 status
= DLADM_STATUS_BADARG
;
999 rv
= snprintf(dev
, len
, "%s%d", drv
, vid
* 1000 + ppa
);
1001 status
= DLADM_STATUS_FAILED
;
1002 else if ((size_t)rv
>= len
)
1003 status
= DLADM_STATUS_TOOSMALL
;
1005 if (strlcpy(dev
, devname
, len
) >= len
)
1006 status
= DLADM_STATUS_TOOSMALL
;
1014 dladm_parselink(const char *dev
, char *provider
, uint_t
*ppa
)
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
);
1025 *ppa
= ifsp
.ifsp_ppa
;
1027 return (DLADM_STATUS_OK
);