1f595a68aSyz147064 /*
2f595a68aSyz147064 * CDDL HEADER START
3f595a68aSyz147064 *
4f595a68aSyz147064 * The contents of this file are subject to the terms of the
5f595a68aSyz147064 * Common Development and Distribution License (the "License").
6f595a68aSyz147064 * You may not use this file except in compliance with the License.
7f595a68aSyz147064 *
8f595a68aSyz147064 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9f595a68aSyz147064 * or http://www.opensolaris.org/os/licensing.
10f595a68aSyz147064 * See the License for the specific language governing permissions
11f595a68aSyz147064 * and limitations under the License.
12f595a68aSyz147064 *
13f595a68aSyz147064 * When distributing Covered Code, include this CDDL HEADER in each
14f595a68aSyz147064 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15f595a68aSyz147064 * If applicable, add the following below this CDDL HEADER, with the
16f595a68aSyz147064 * fields enclosed by brackets "[]" replaced with your own identifying
17f595a68aSyz147064 * information: Portions Copyright [yyyy] [name of copyright owner]
18f595a68aSyz147064 *
19f595a68aSyz147064 * CDDL HEADER END
20f595a68aSyz147064 */
21f595a68aSyz147064 /*
22*32715170SCathy Zhou * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23f595a68aSyz147064 */
24f595a68aSyz147064
25f595a68aSyz147064 #include <stdio.h>
26f595a68aSyz147064 #include <sys/types.h>
27f595a68aSyz147064 #include <sys/stat.h>
28f595a68aSyz147064 #include <string.h>
29f595a68aSyz147064 #include <fcntl.h>
30f595a68aSyz147064 #include <unistd.h>
31f595a68aSyz147064 #include <stropts.h>
32f595a68aSyz147064 #include <stdlib.h>
33f595a68aSyz147064 #include <errno.h>
34d62bc4baSyz147064 #include <assert.h>
35f595a68aSyz147064 #include <strings.h>
36f595a68aSyz147064 #include <libintl.h>
37f595a68aSyz147064 #include <net/if_types.h>
38f595a68aSyz147064 #include <net/if_dl.h>
39da14cebeSEric Cheng #include <sys/dld.h>
40d62bc4baSyz147064 #include <libdllink.h>
41d62bc4baSyz147064 #include <libdlvlan.h>
42f595a68aSyz147064 #include <libdlaggr.h>
43f595a68aSyz147064 #include <libdladm_impl.h>
44f595a68aSyz147064
45f595a68aSyz147064 /*
46f595a68aSyz147064 * Link Aggregation Administration Library.
47f595a68aSyz147064 *
48f595a68aSyz147064 * This library is used by administration tools such as dladm(1M) to
49f595a68aSyz147064 * configure link aggregations.
50f595a68aSyz147064 */
51f595a68aSyz147064
52f595a68aSyz147064 /* Limits on buffer size for LAIOC_INFO request */
53f595a68aSyz147064 #define MIN_INFO_SIZE (4*1024)
54f595a68aSyz147064 #define MAX_INFO_SIZE (128*1024)
55f595a68aSyz147064
56f595a68aSyz147064 static uchar_t zero_mac[] = {0, 0, 0, 0, 0, 0};
57d62bc4baSyz147064 #define VALID_PORT_MAC(mac) \
58d62bc4baSyz147064 (((mac) != NULL) && (bcmp(zero_mac, (mac), ETHERADDRL) != 0) && \
590dc2366fSVenugopal Iyer (!((mac)[0] & 0x01)))
60f595a68aSyz147064
612b24ab6bSSebastien Roy #define PORT_DELIMITER ":"
62f595a68aSyz147064
63f595a68aSyz147064 typedef struct dladm_aggr_modify_attr {
64f595a68aSyz147064 uint32_t ld_policy;
65f595a68aSyz147064 boolean_t ld_mac_fixed;
66f595a68aSyz147064 uchar_t ld_mac[ETHERADDRL];
67f595a68aSyz147064 aggr_lacp_mode_t ld_lacp_mode;
68f595a68aSyz147064 aggr_lacp_timer_t ld_lacp_timer;
69f595a68aSyz147064 } dladm_aggr_modify_attr_t;
70f595a68aSyz147064
71f595a68aSyz147064 typedef struct policy_s {
72f595a68aSyz147064 char *pol_name;
73f595a68aSyz147064 uint32_t policy;
74f595a68aSyz147064 } policy_t;
75f595a68aSyz147064
76f595a68aSyz147064 static policy_t policies[] = {
77f595a68aSyz147064 {"L2", AGGR_POLICY_L2},
78f595a68aSyz147064 {"L3", AGGR_POLICY_L3},
79f595a68aSyz147064 {"L4", AGGR_POLICY_L4}};
80f595a68aSyz147064
81f595a68aSyz147064 #define NPOLICIES (sizeof (policies) / sizeof (policy_t))
82f595a68aSyz147064
83f595a68aSyz147064 typedef struct dladm_aggr_lacpmode_s {
84f595a68aSyz147064 char *mode_str;
85f595a68aSyz147064 aggr_lacp_mode_t mode_id;
86f595a68aSyz147064 } dladm_aggr_lacpmode_t;
87f595a68aSyz147064
88f595a68aSyz147064 static dladm_aggr_lacpmode_t lacp_modes[] = {
89f595a68aSyz147064 {"off", AGGR_LACP_OFF},
90f595a68aSyz147064 {"active", AGGR_LACP_ACTIVE},
91f595a68aSyz147064 {"passive", AGGR_LACP_PASSIVE}};
92f595a68aSyz147064
93f595a68aSyz147064 #define NLACP_MODES (sizeof (lacp_modes) / sizeof (dladm_aggr_lacpmode_t))
94f595a68aSyz147064
95f595a68aSyz147064 typedef struct dladm_aggr_lacptimer_s {
96f595a68aSyz147064 char *lt_str;
97f595a68aSyz147064 aggr_lacp_timer_t lt_id;
98f595a68aSyz147064 } dladm_aggr_lacptimer_t;
99f595a68aSyz147064
100f595a68aSyz147064 static dladm_aggr_lacptimer_t lacp_timers[] = {
101f595a68aSyz147064 {"short", AGGR_LACP_TIMER_SHORT},
102f595a68aSyz147064 {"long", AGGR_LACP_TIMER_LONG}};
103f595a68aSyz147064
104f595a68aSyz147064 #define NLACP_TIMERS (sizeof (lacp_timers) / sizeof (dladm_aggr_lacptimer_t))
105f595a68aSyz147064
106f595a68aSyz147064 typedef struct dladm_aggr_port_state {
107f595a68aSyz147064 char *state_str;
108f595a68aSyz147064 aggr_port_state_t state_id;
109f595a68aSyz147064 } dladm_aggr_port_state_t;
110f595a68aSyz147064
111f595a68aSyz147064 static dladm_aggr_port_state_t port_states[] = {
112f595a68aSyz147064 {"standby", AGGR_PORT_STATE_STANDBY },
113f595a68aSyz147064 {"attached", AGGR_PORT_STATE_ATTACHED }
114f595a68aSyz147064 };
115f595a68aSyz147064
116f595a68aSyz147064 #define NPORT_STATES \
117f595a68aSyz147064 (sizeof (port_states) / sizeof (dladm_aggr_port_state_t))
118f595a68aSyz147064
1192b24ab6bSSebastien Roy static dladm_status_t
write_port(dladm_handle_t handle,char * portstr,datalink_id_t portid,size_t portstrsize)1202b24ab6bSSebastien Roy write_port(dladm_handle_t handle, char *portstr, datalink_id_t portid,
1212b24ab6bSSebastien Roy size_t portstrsize)
1222b24ab6bSSebastien Roy {
1232b24ab6bSSebastien Roy char pname[MAXLINKNAMELEN + 1];
1242b24ab6bSSebastien Roy dladm_status_t status;
1252b24ab6bSSebastien Roy
1262b24ab6bSSebastien Roy if ((status = dladm_datalink_id2info(handle, portid, NULL, NULL, NULL,
1272b24ab6bSSebastien Roy pname, sizeof (pname))) != DLADM_STATUS_OK)
1282b24ab6bSSebastien Roy return (status);
1292b24ab6bSSebastien Roy (void) strlcat(pname, PORT_DELIMITER, sizeof (pname));
1302b24ab6bSSebastien Roy if (strlcat(portstr, pname, portstrsize) >= portstrsize)
1312b24ab6bSSebastien Roy status = DLADM_STATUS_TOOSMALL;
1322b24ab6bSSebastien Roy return (status);
1332b24ab6bSSebastien Roy }
1342b24ab6bSSebastien Roy
1352b24ab6bSSebastien Roy static dladm_status_t
read_port(dladm_handle_t handle,char ** portstr,datalink_id_t * portid)1362b24ab6bSSebastien Roy read_port(dladm_handle_t handle, char **portstr, datalink_id_t *portid)
1372b24ab6bSSebastien Roy {
1382b24ab6bSSebastien Roy dladm_status_t status;
1392b24ab6bSSebastien Roy char *pname;
1402b24ab6bSSebastien Roy
1412b24ab6bSSebastien Roy if ((pname = strtok(*portstr, PORT_DELIMITER)) == NULL)
1422b24ab6bSSebastien Roy return (DLADM_STATUS_REPOSITORYINVAL);
1432b24ab6bSSebastien Roy *portstr += (strlen(pname) + 1);
1442b24ab6bSSebastien Roy status = dladm_name2info(handle, pname, portid, NULL, NULL, NULL);
1452b24ab6bSSebastien Roy return (status);
1462b24ab6bSSebastien Roy }
1472b24ab6bSSebastien Roy
148d62bc4baSyz147064 static int
i_dladm_aggr_ioctl(dladm_handle_t handle,int cmd,void * ptr)1494ac67f02SAnurag S. Maskey i_dladm_aggr_ioctl(dladm_handle_t handle, int cmd, void *ptr)
150d62bc4baSyz147064 {
1514ac67f02SAnurag S. Maskey return (ioctl(dladm_dld_fd(handle), cmd, ptr));
152d62bc4baSyz147064 }
153f595a68aSyz147064
154f595a68aSyz147064 /*
155d62bc4baSyz147064 * Caller must free attr.lg_ports. The ptr pointer is advanced while convert
156d62bc4baSyz147064 * the laioc_info_t to the dladm_aggr_grp_attr_t structure.
157f595a68aSyz147064 */
158f595a68aSyz147064 static int
i_dladm_aggr_iocp2grpattr(void ** ptr,dladm_aggr_grp_attr_t * attrp)159d62bc4baSyz147064 i_dladm_aggr_iocp2grpattr(void **ptr, dladm_aggr_grp_attr_t *attrp)
160f595a68aSyz147064 {
161f595a68aSyz147064 laioc_info_group_t *grp;
162f595a68aSyz147064 laioc_info_port_t *port;
163d62bc4baSyz147064 int i;
164d62bc4baSyz147064 void *where = (*ptr);
165f595a68aSyz147064
166d62bc4baSyz147064 grp = (laioc_info_group_t *)where;
167d62bc4baSyz147064
168d62bc4baSyz147064 attrp->lg_linkid = grp->lg_linkid;
169d62bc4baSyz147064 attrp->lg_key = grp->lg_key;
170d62bc4baSyz147064 attrp->lg_nports = grp->lg_nports;
171d62bc4baSyz147064 attrp->lg_policy = grp->lg_policy;
172d62bc4baSyz147064 attrp->lg_lacp_mode = grp->lg_lacp_mode;
173d62bc4baSyz147064 attrp->lg_lacp_timer = grp->lg_lacp_timer;
174d62bc4baSyz147064 attrp->lg_force = grp->lg_force;
175d62bc4baSyz147064
176d62bc4baSyz147064 bcopy(grp->lg_mac, attrp->lg_mac, ETHERADDRL);
177d62bc4baSyz147064 attrp->lg_mac_fixed = grp->lg_mac_fixed;
178d62bc4baSyz147064
179d62bc4baSyz147064 if ((attrp->lg_ports = malloc(grp->lg_nports *
180d62bc4baSyz147064 sizeof (dladm_aggr_port_attr_t))) == NULL) {
181d62bc4baSyz147064 errno = ENOMEM;
182d62bc4baSyz147064 goto fail;
183d62bc4baSyz147064 }
184d62bc4baSyz147064
185d62bc4baSyz147064 where = (grp + 1);
186d62bc4baSyz147064
187d62bc4baSyz147064 /*
188d62bc4baSyz147064 * Go through each port that is part of the group.
189d62bc4baSyz147064 */
190d62bc4baSyz147064 for (i = 0; i < grp->lg_nports; i++) {
191d62bc4baSyz147064 port = (laioc_info_port_t *)where;
192d62bc4baSyz147064
193d62bc4baSyz147064 attrp->lg_ports[i].lp_linkid = port->lp_linkid;
194d62bc4baSyz147064 bcopy(port->lp_mac, attrp->lg_ports[i].lp_mac, ETHERADDRL);
195d62bc4baSyz147064 attrp->lg_ports[i].lp_state = port->lp_state;
196d62bc4baSyz147064 attrp->lg_ports[i].lp_lacp_state = port->lp_lacp_state;
197d62bc4baSyz147064
198d62bc4baSyz147064 where = (port + 1);
199d62bc4baSyz147064 }
200d62bc4baSyz147064 *ptr = where;
201d62bc4baSyz147064 return (0);
202d62bc4baSyz147064 fail:
203f595a68aSyz147064 return (-1);
204d62bc4baSyz147064 }
205d62bc4baSyz147064
206d62bc4baSyz147064 /*
207d62bc4baSyz147064 * Get active configuration of a specific aggregation.
208d62bc4baSyz147064 * Caller must free attrp->la_ports.
209d62bc4baSyz147064 */
210d62bc4baSyz147064 static dladm_status_t
i_dladm_aggr_info_active(dladm_handle_t handle,datalink_id_t linkid,dladm_aggr_grp_attr_t * attrp)2114ac67f02SAnurag S. Maskey i_dladm_aggr_info_active(dladm_handle_t handle, datalink_id_t linkid,
2124ac67f02SAnurag S. Maskey dladm_aggr_grp_attr_t *attrp)
213d62bc4baSyz147064 {
214d62bc4baSyz147064 laioc_info_t *ioc;
215eae72b5bSSebastien Roy int bufsize;
216d62bc4baSyz147064 void *where;
217d62bc4baSyz147064 dladm_status_t status = DLADM_STATUS_OK;
218f595a68aSyz147064
219f595a68aSyz147064 bufsize = MIN_INFO_SIZE;
220f595a68aSyz147064 ioc = (laioc_info_t *)calloc(1, bufsize);
221d62bc4baSyz147064 if (ioc == NULL)
222d62bc4baSyz147064 return (DLADM_STATUS_NOMEM);
223d62bc4baSyz147064
224d62bc4baSyz147064 ioc->li_group_linkid = linkid;
225f595a68aSyz147064
226f595a68aSyz147064 tryagain:
227eae72b5bSSebastien Roy ioc->li_bufsize = bufsize;
2284ac67f02SAnurag S. Maskey if (i_dladm_aggr_ioctl(handle, LAIOC_INFO, ioc) != 0) {
229f595a68aSyz147064 if (errno == ENOSPC) {
230f595a68aSyz147064 /*
231f595a68aSyz147064 * The LAIOC_INFO call failed due to a short
232f595a68aSyz147064 * buffer. Reallocate the buffer and try again.
233f595a68aSyz147064 */
234f595a68aSyz147064 bufsize *= 2;
235f595a68aSyz147064 if (bufsize <= MAX_INFO_SIZE) {
236f595a68aSyz147064 ioc = (laioc_info_t *)realloc(ioc, bufsize);
237f595a68aSyz147064 if (ioc != NULL) {
238f595a68aSyz147064 bzero(ioc, sizeof (bufsize));
239f595a68aSyz147064 goto tryagain;
240f595a68aSyz147064 }
241f595a68aSyz147064 }
242f595a68aSyz147064 }
243d62bc4baSyz147064 status = dladm_errno2status(errno);
244f595a68aSyz147064 goto bail;
245f595a68aSyz147064 }
246f595a68aSyz147064
247f595a68aSyz147064 /*
248f595a68aSyz147064 * Go through each group returned by the aggregation driver.
249f595a68aSyz147064 */
250f595a68aSyz147064 where = (char *)(ioc + 1);
251d62bc4baSyz147064 if (i_dladm_aggr_iocp2grpattr(&where, attrp) != 0) {
252d62bc4baSyz147064 status = dladm_errno2status(errno);
253f595a68aSyz147064 goto bail;
254f595a68aSyz147064 }
255f595a68aSyz147064
256f595a68aSyz147064 bail:
257f595a68aSyz147064 free(ioc);
258f595a68aSyz147064 return (status);
259f595a68aSyz147064 }
260f595a68aSyz147064
261d62bc4baSyz147064 /*
262d62bc4baSyz147064 * Get configuration information of a specific aggregation.
263d62bc4baSyz147064 * Caller must free attrp->la_ports.
264d62bc4baSyz147064 */
265d62bc4baSyz147064 static dladm_status_t
i_dladm_aggr_info_persist(dladm_handle_t handle,datalink_id_t linkid,dladm_aggr_grp_attr_t * attrp)2664ac67f02SAnurag S. Maskey i_dladm_aggr_info_persist(dladm_handle_t handle, datalink_id_t linkid,
2674ac67f02SAnurag S. Maskey dladm_aggr_grp_attr_t *attrp)
268d62bc4baSyz147064 {
269d62bc4baSyz147064 dladm_conf_t conf;
270d62bc4baSyz147064 uint32_t nports, i;
2712b24ab6bSSebastien Roy char *portstr = NULL, *next;
272d62bc4baSyz147064 dladm_status_t status;
273d62bc4baSyz147064 uint64_t u64;
274d62bc4baSyz147064 int size;
275d62bc4baSyz147064 char macstr[ETHERADDRL * 3];
276f595a68aSyz147064
277d62bc4baSyz147064 attrp->lg_linkid = linkid;
278*32715170SCathy Zhou if ((status = dladm_getsnap_conf(handle, linkid, &conf)) !=
2794ac67f02SAnurag S. Maskey DLADM_STATUS_OK)
280d62bc4baSyz147064 return (status);
281f595a68aSyz147064
2824ac67f02SAnurag S. Maskey status = dladm_get_conf_field(handle, conf, FKEY, &u64, sizeof (u64));
283d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
284d62bc4baSyz147064 goto done;
285d62bc4baSyz147064 attrp->lg_key = (uint16_t)u64;
286d62bc4baSyz147064
2874ac67f02SAnurag S. Maskey status = dladm_get_conf_field(handle, conf, FPOLICY, &u64,
2884ac67f02SAnurag S. Maskey sizeof (u64));
289d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
290d62bc4baSyz147064 goto done;
291d62bc4baSyz147064 attrp->lg_policy = (uint32_t)u64;
292d62bc4baSyz147064
2934ac67f02SAnurag S. Maskey status = dladm_get_conf_field(handle, conf, FFIXMACADDR,
2944ac67f02SAnurag S. Maskey &attrp->lg_mac_fixed, sizeof (boolean_t));
295d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
296d62bc4baSyz147064 goto done;
297d62bc4baSyz147064
298d62bc4baSyz147064 if (attrp->lg_mac_fixed) {
299d62bc4baSyz147064 boolean_t fixed;
300d62bc4baSyz147064
3014ac67f02SAnurag S. Maskey if ((status = dladm_get_conf_field(handle, conf, FMACADDR,
3024ac67f02SAnurag S. Maskey macstr, sizeof (macstr))) != DLADM_STATUS_OK) {
303d62bc4baSyz147064 goto done;
304d62bc4baSyz147064 }
305d62bc4baSyz147064 if (!dladm_aggr_str2macaddr(macstr, &fixed, attrp->lg_mac)) {
306f595a68aSyz147064 status = DLADM_STATUS_REPOSITORYINVAL;
307f595a68aSyz147064 goto done;
308f595a68aSyz147064 }
309d62bc4baSyz147064 }
310f595a68aSyz147064
3114ac67f02SAnurag S. Maskey status = dladm_get_conf_field(handle, conf, FFORCE, &attrp->lg_force,
312d62bc4baSyz147064 sizeof (boolean_t));
313d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
314f595a68aSyz147064 goto done;
315f595a68aSyz147064
3164ac67f02SAnurag S. Maskey status = dladm_get_conf_field(handle, conf, FLACPMODE, &u64,
3174ac67f02SAnurag S. Maskey sizeof (u64));
318d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
319d62bc4baSyz147064 goto done;
320d62bc4baSyz147064 attrp->lg_lacp_mode = (aggr_lacp_mode_t)u64;
321f595a68aSyz147064
3224ac67f02SAnurag S. Maskey status = dladm_get_conf_field(handle, conf, FLACPTIMER, &u64,
3234ac67f02SAnurag S. Maskey sizeof (u64));
324d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
325d62bc4baSyz147064 goto done;
326d62bc4baSyz147064 attrp->lg_lacp_timer = (aggr_lacp_timer_t)u64;
327f595a68aSyz147064
3284ac67f02SAnurag S. Maskey status = dladm_get_conf_field(handle, conf, FNPORTS, &u64,
3294ac67f02SAnurag S. Maskey sizeof (u64));
330d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
331d62bc4baSyz147064 goto done;
332d62bc4baSyz147064 nports = (uint32_t)u64;
333d62bc4baSyz147064 attrp->lg_nports = nports;
334f595a68aSyz147064
3352b24ab6bSSebastien Roy size = nports * (MAXLINKNAMELEN + 1) + 1;
336d62bc4baSyz147064 if ((portstr = calloc(1, size)) == NULL) {
337f595a68aSyz147064 status = DLADM_STATUS_NOMEM;
338f595a68aSyz147064 goto done;
339f595a68aSyz147064 }
340f595a68aSyz147064
3414ac67f02SAnurag S. Maskey status = dladm_get_conf_field(handle, conf, FPORTS, portstr, size);
3422b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK)
343f595a68aSyz147064 goto done;
344f595a68aSyz147064
345d62bc4baSyz147064 if ((attrp->lg_ports = malloc(nports *
346d62bc4baSyz147064 sizeof (dladm_aggr_port_attr_t))) == NULL) {
347d62bc4baSyz147064 status = DLADM_STATUS_NOMEM;
348d62bc4baSyz147064 goto done;
349d62bc4baSyz147064 }
350d62bc4baSyz147064
351d62bc4baSyz147064 for (next = portstr, i = 0; i < nports; i++) {
3522b24ab6bSSebastien Roy if ((status = read_port(handle, &next,
3532b24ab6bSSebastien Roy &attrp->lg_ports[i].lp_linkid)) != DLADM_STATUS_OK)
354d62bc4baSyz147064 free(attrp->lg_ports);
355d62bc4baSyz147064 }
356d62bc4baSyz147064
357d62bc4baSyz147064 done:
3582b24ab6bSSebastien Roy free(portstr);
3594ac67f02SAnurag S. Maskey dladm_destroy_conf(handle, conf);
360d62bc4baSyz147064 return (status);
361d62bc4baSyz147064 }
362d62bc4baSyz147064
363d62bc4baSyz147064 dladm_status_t
dladm_aggr_info(dladm_handle_t handle,datalink_id_t linkid,dladm_aggr_grp_attr_t * attrp,uint32_t flags)3644ac67f02SAnurag S. Maskey dladm_aggr_info(dladm_handle_t handle, datalink_id_t linkid,
3654ac67f02SAnurag S. Maskey dladm_aggr_grp_attr_t *attrp, uint32_t flags)
366d62bc4baSyz147064 {
367d62bc4baSyz147064 assert(flags == DLADM_OPT_ACTIVE || flags == DLADM_OPT_PERSIST);
368d62bc4baSyz147064 if (flags == DLADM_OPT_ACTIVE)
3694ac67f02SAnurag S. Maskey return (i_dladm_aggr_info_active(handle, linkid, attrp));
370f595a68aSyz147064 else
3714ac67f02SAnurag S. Maskey return (i_dladm_aggr_info_persist(handle, linkid, attrp));
372f595a68aSyz147064 }
373f595a68aSyz147064
374d62bc4baSyz147064 /*
375d62bc4baSyz147064 * Add or remove one or more ports to/from an existing link aggregation.
376d62bc4baSyz147064 */
377d62bc4baSyz147064 static dladm_status_t
i_dladm_aggr_add_rmv(dladm_handle_t handle,datalink_id_t linkid,uint32_t nports,dladm_aggr_port_attr_db_t * ports,uint32_t flags,int cmd)3784ac67f02SAnurag S. Maskey i_dladm_aggr_add_rmv(dladm_handle_t handle, datalink_id_t linkid,
3794ac67f02SAnurag S. Maskey uint32_t nports, dladm_aggr_port_attr_db_t *ports, uint32_t flags, int cmd)
380d62bc4baSyz147064 {
381d62bc4baSyz147064 char *orig_portstr = NULL, *portstr = NULL;
3828de9d095Syz147064 laioc_add_rem_t *iocp = NULL;
383d62bc4baSyz147064 laioc_port_t *ioc_ports;
384d62bc4baSyz147064 uint32_t orig_nports, result_nports, len, i, j;
385d62bc4baSyz147064 dladm_conf_t conf;
386d62bc4baSyz147064 datalink_class_t class;
387d62bc4baSyz147064 dladm_status_t status = DLADM_STATUS_OK;
388d62bc4baSyz147064 int size;
389d62bc4baSyz147064 uint64_t u64;
390d62bc4baSyz147064 uint32_t media;
391d62bc4baSyz147064
392d62bc4baSyz147064 if (nports == 0)
393d62bc4baSyz147064 return (DLADM_STATUS_BADARG);
394d62bc4baSyz147064
395d62bc4baSyz147064 /*
396d62bc4baSyz147064 * Sanity check - aggregations can only be created over Ethernet
397b509e89bSRishi Srivatsavai * physical links and simnets.
398d62bc4baSyz147064 */
399d62bc4baSyz147064 for (i = 0; i < nports; i++) {
4004ac67f02SAnurag S. Maskey if ((dladm_datalink_id2info(handle, ports[i].lp_linkid, NULL,
401d62bc4baSyz147064 &class, &media, NULL, 0) != DLADM_STATUS_OK) ||
402b509e89bSRishi Srivatsavai !((class == DATALINK_CLASS_PHYS) ||
403b509e89bSRishi Srivatsavai (class == DATALINK_CLASS_SIMNET)) || (media != DL_ETHER)) {
404d62bc4baSyz147064 return (DLADM_STATUS_BADARG);
405d62bc4baSyz147064 }
406d62bc4baSyz147064 }
407d62bc4baSyz147064
408d62bc4baSyz147064 /*
409d62bc4baSyz147064 * First, update the persistent configuration if requested. We only
410d62bc4baSyz147064 * need to update the FPORTS and FNPORTS fields of this aggregation.
411d62bc4baSyz147064 * Note that FPORTS is a list of port linkids separated by
4122b24ab6bSSebastien Roy * PORT_DELIMITER (':').
413d62bc4baSyz147064 */
414d62bc4baSyz147064 if (flags & DLADM_OPT_PERSIST) {
415*32715170SCathy Zhou status = dladm_open_conf(handle, linkid, &conf);
416d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
417d62bc4baSyz147064 return (status);
418d62bc4baSyz147064
419d62bc4baSyz147064 /*
420d62bc4baSyz147064 * Get the original configuration of FNPORTS and FPORTS.
421d62bc4baSyz147064 */
4224ac67f02SAnurag S. Maskey status = dladm_get_conf_field(handle, conf, FNPORTS, &u64,
423d62bc4baSyz147064 sizeof (u64));
424d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
425d62bc4baSyz147064 goto destroyconf;
426d62bc4baSyz147064 orig_nports = (uint32_t)u64;
427d62bc4baSyz147064
428d62bc4baSyz147064 /*
429d62bc4baSyz147064 * At least one port needs to be in the aggregation.
430d62bc4baSyz147064 */
431d62bc4baSyz147064 if ((cmd == LAIOC_REMOVE) && (orig_nports <= nports)) {
432d62bc4baSyz147064 status = DLADM_STATUS_BADARG;
433d62bc4baSyz147064 goto destroyconf;
434d62bc4baSyz147064 }
435d62bc4baSyz147064
4362b24ab6bSSebastien Roy size = orig_nports * (MAXLINKNAMELEN + 1) + 1;
437d62bc4baSyz147064 if ((orig_portstr = calloc(1, size)) == NULL) {
438d62bc4baSyz147064 status = dladm_errno2status(errno);
439d62bc4baSyz147064 goto destroyconf;
440d62bc4baSyz147064 }
441d62bc4baSyz147064
4424ac67f02SAnurag S. Maskey status = dladm_get_conf_field(handle, conf, FPORTS,
4434ac67f02SAnurag S. Maskey orig_portstr, size);
444d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
445d62bc4baSyz147064 goto destroyconf;
446d62bc4baSyz147064
447d62bc4baSyz147064 result_nports = (cmd == LAIOC_ADD) ? orig_nports + nports :
448d62bc4baSyz147064 orig_nports;
449d62bc4baSyz147064
4502b24ab6bSSebastien Roy size = result_nports * (MAXLINKNAMELEN + 1) + 1;
451d62bc4baSyz147064 if ((portstr = calloc(1, size)) == NULL) {
452d62bc4baSyz147064 status = dladm_errno2status(errno);
453d62bc4baSyz147064 goto destroyconf;
454d62bc4baSyz147064 }
455d62bc4baSyz147064
456d62bc4baSyz147064 /*
457d62bc4baSyz147064 * get the new configuration and set to result_nports and
458d62bc4baSyz147064 * portstr.
459d62bc4baSyz147064 */
460d62bc4baSyz147064 if (cmd == LAIOC_ADD) {
461d62bc4baSyz147064 (void) strlcpy(portstr, orig_portstr, size);
4622b24ab6bSSebastien Roy for (i = 0; i < nports; i++) {
4632b24ab6bSSebastien Roy status = write_port(handle, portstr,
4642b24ab6bSSebastien Roy ports[i].lp_linkid, size);
4652b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) {
4662b24ab6bSSebastien Roy free(portstr);
4672b24ab6bSSebastien Roy goto destroyconf;
4682b24ab6bSSebastien Roy }
4692b24ab6bSSebastien Roy }
470d62bc4baSyz147064 } else {
471d62bc4baSyz147064 char *next;
472d62bc4baSyz147064 datalink_id_t portid;
473d62bc4baSyz147064 uint32_t remove = 0;
474d62bc4baSyz147064
475d62bc4baSyz147064 for (next = orig_portstr, j = 0; j < orig_nports; j++) {
476d62bc4baSyz147064 /*
477d62bc4baSyz147064 * Read the portids from the old configuration
478d62bc4baSyz147064 * one by one.
479d62bc4baSyz147064 */
4802b24ab6bSSebastien Roy status = read_port(handle, &next, &portid);
481d62bc4baSyz147064 if (status != DLADM_STATUS_OK) {
482d62bc4baSyz147064 free(portstr);
483d62bc4baSyz147064 goto destroyconf;
484d62bc4baSyz147064 }
485d62bc4baSyz147064
486d62bc4baSyz147064 /*
487d62bc4baSyz147064 * See whether this port is in the removal
488d62bc4baSyz147064 * list. If not, copy to the new config.
489d62bc4baSyz147064 */
490d62bc4baSyz147064 for (i = 0; i < nports; i++) {
491d62bc4baSyz147064 if (ports[i].lp_linkid == portid)
492d62bc4baSyz147064 break;
493d62bc4baSyz147064 }
494d62bc4baSyz147064 if (i == nports) {
4952b24ab6bSSebastien Roy status = write_port(handle, portstr,
4962b24ab6bSSebastien Roy portid, size);
4972b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) {
4982b24ab6bSSebastien Roy free(portstr);
4992b24ab6bSSebastien Roy goto destroyconf;
5002b24ab6bSSebastien Roy }
501d62bc4baSyz147064 } else {
502d62bc4baSyz147064 remove++;
503d62bc4baSyz147064 }
504d62bc4baSyz147064 }
505d62bc4baSyz147064 if (remove != nports) {
506d62bc4baSyz147064 status = DLADM_STATUS_LINKINVAL;
507d62bc4baSyz147064 free(portstr);
508d62bc4baSyz147064 goto destroyconf;
509d62bc4baSyz147064 }
510d62bc4baSyz147064 result_nports -= nports;
511d62bc4baSyz147064 }
512d62bc4baSyz147064
513d62bc4baSyz147064 u64 = result_nports;
5144ac67f02SAnurag S. Maskey if ((status = dladm_set_conf_field(handle, conf, FNPORTS,
515d62bc4baSyz147064 DLADM_TYPE_UINT64, &u64)) != DLADM_STATUS_OK) {
516d62bc4baSyz147064 free(portstr);
517d62bc4baSyz147064 goto destroyconf;
518d62bc4baSyz147064 }
519d62bc4baSyz147064
5204ac67f02SAnurag S. Maskey status = dladm_set_conf_field(handle, conf, FPORTS,
5214ac67f02SAnurag S. Maskey DLADM_TYPE_STR, portstr);
522d62bc4baSyz147064 free(portstr);
523d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
524d62bc4baSyz147064 goto destroyconf;
525d62bc4baSyz147064
526d62bc4baSyz147064 /*
527d62bc4baSyz147064 * Write the new configuration to the persistent repository.
528d62bc4baSyz147064 */
5294ac67f02SAnurag S. Maskey status = dladm_write_conf(handle, conf);
530d62bc4baSyz147064
531d62bc4baSyz147064 destroyconf:
5324ac67f02SAnurag S. Maskey dladm_destroy_conf(handle, conf);
533d62bc4baSyz147064 if (status != DLADM_STATUS_OK) {
534d62bc4baSyz147064 free(orig_portstr);
535d62bc4baSyz147064 return (status);
536d62bc4baSyz147064 }
537d62bc4baSyz147064 }
538d62bc4baSyz147064
539d62bc4baSyz147064 /*
540d62bc4baSyz147064 * If the caller only requested to update the persistent
541d62bc4baSyz147064 * configuration, we are done.
542d62bc4baSyz147064 */
543d62bc4baSyz147064 if (!(flags & DLADM_OPT_ACTIVE))
544d62bc4baSyz147064 goto done;
545d62bc4baSyz147064
546d62bc4baSyz147064 /*
547d62bc4baSyz147064 * Update the active configuration.
548d62bc4baSyz147064 */
549d62bc4baSyz147064 len = sizeof (*iocp) + nports * sizeof (laioc_port_t);
550d62bc4baSyz147064 if ((iocp = malloc(len)) == NULL) {
551d62bc4baSyz147064 status = DLADM_STATUS_NOMEM;
552d62bc4baSyz147064 goto done;
553d62bc4baSyz147064 }
554d62bc4baSyz147064
555d62bc4baSyz147064 iocp->la_linkid = linkid;
556d62bc4baSyz147064 iocp->la_nports = nports;
557d62bc4baSyz147064 if (cmd == LAIOC_ADD)
558d62bc4baSyz147064 iocp->la_force = (flags & DLADM_OPT_FORCE);
559d62bc4baSyz147064
560d62bc4baSyz147064 ioc_ports = (laioc_port_t *)(iocp + 1);
561d62bc4baSyz147064 for (i = 0; i < nports; i++)
562d62bc4baSyz147064 ioc_ports[i].lp_linkid = ports[i].lp_linkid;
563d62bc4baSyz147064
5644ac67f02SAnurag S. Maskey if (i_dladm_aggr_ioctl(handle, cmd, iocp) < 0)
565d62bc4baSyz147064 status = dladm_errno2status(errno);
566f595a68aSyz147064
567f595a68aSyz147064 done:
568f595a68aSyz147064 free(iocp);
569d62bc4baSyz147064
570d62bc4baSyz147064 /*
571d62bc4baSyz147064 * If the active configuration update fails, restore the old
572d62bc4baSyz147064 * persistent configuration if we've changed that.
573d62bc4baSyz147064 */
574d62bc4baSyz147064 if ((status != DLADM_STATUS_OK) && (flags & DLADM_OPT_PERSIST)) {
575*32715170SCathy Zhou if (dladm_open_conf(handle, linkid, &conf) == DLADM_STATUS_OK) {
576d62bc4baSyz147064 u64 = orig_nports;
5774ac67f02SAnurag S. Maskey if ((dladm_set_conf_field(handle, conf, FNPORTS,
578d62bc4baSyz147064 DLADM_TYPE_UINT64, &u64) == DLADM_STATUS_OK) &&
5794ac67f02SAnurag S. Maskey (dladm_set_conf_field(handle, conf, FPORTS,
5804ac67f02SAnurag S. Maskey DLADM_TYPE_STR, orig_portstr) == DLADM_STATUS_OK)) {
5814ac67f02SAnurag S. Maskey (void) dladm_write_conf(handle, conf);
582d62bc4baSyz147064 }
5834ac67f02SAnurag S. Maskey (void) dladm_destroy_conf(handle, conf);
584d62bc4baSyz147064 }
585d62bc4baSyz147064 }
586d62bc4baSyz147064 free(orig_portstr);
587f595a68aSyz147064 return (status);
588f595a68aSyz147064 }
589f595a68aSyz147064
590f595a68aSyz147064 /*
591f595a68aSyz147064 * Send a modify command to the link aggregation driver.
592f595a68aSyz147064 */
593f595a68aSyz147064 static dladm_status_t
i_dladm_aggr_modify_sys(dladm_handle_t handle,datalink_id_t linkid,uint32_t mask,dladm_aggr_modify_attr_t * attr)5944ac67f02SAnurag S. Maskey i_dladm_aggr_modify_sys(dladm_handle_t handle, datalink_id_t linkid,
5954ac67f02SAnurag S. Maskey uint32_t mask, dladm_aggr_modify_attr_t *attr)
596f595a68aSyz147064 {
597f595a68aSyz147064 laioc_modify_t ioc;
598f595a68aSyz147064
599d62bc4baSyz147064 ioc.lu_linkid = linkid;
600f595a68aSyz147064
601f595a68aSyz147064 ioc.lu_modify_mask = 0;
602f595a68aSyz147064 if (mask & DLADM_AGGR_MODIFY_POLICY)
603f595a68aSyz147064 ioc.lu_modify_mask |= LAIOC_MODIFY_POLICY;
604f595a68aSyz147064 if (mask & DLADM_AGGR_MODIFY_MAC)
605f595a68aSyz147064 ioc.lu_modify_mask |= LAIOC_MODIFY_MAC;
606f595a68aSyz147064 if (mask & DLADM_AGGR_MODIFY_LACP_MODE)
607f595a68aSyz147064 ioc.lu_modify_mask |= LAIOC_MODIFY_LACP_MODE;
608f595a68aSyz147064 if (mask & DLADM_AGGR_MODIFY_LACP_TIMER)
609f595a68aSyz147064 ioc.lu_modify_mask |= LAIOC_MODIFY_LACP_TIMER;
610f595a68aSyz147064
611f595a68aSyz147064 ioc.lu_policy = attr->ld_policy;
612f595a68aSyz147064 ioc.lu_mac_fixed = attr->ld_mac_fixed;
613f595a68aSyz147064 bcopy(attr->ld_mac, ioc.lu_mac, ETHERADDRL);
614f595a68aSyz147064 ioc.lu_lacp_mode = attr->ld_lacp_mode;
615f595a68aSyz147064 ioc.lu_lacp_timer = attr->ld_lacp_timer;
616f595a68aSyz147064
6174ac67f02SAnurag S. Maskey if (i_dladm_aggr_ioctl(handle, LAIOC_MODIFY, &ioc) < 0) {
618f595a68aSyz147064 if (errno == EINVAL)
619d62bc4baSyz147064 return (DLADM_STATUS_MACADDRINVAL);
620f595a68aSyz147064 else
621d62bc4baSyz147064 return (dladm_errno2status(errno));
622d62bc4baSyz147064 } else {
623d62bc4baSyz147064 return (DLADM_STATUS_OK);
624f595a68aSyz147064 }
625f595a68aSyz147064 }
626f595a68aSyz147064
627f595a68aSyz147064 /*
628f595a68aSyz147064 * Send a create command to the link aggregation driver.
629f595a68aSyz147064 */
630f595a68aSyz147064 static dladm_status_t
i_dladm_aggr_create_sys(dladm_handle_t handle,datalink_id_t linkid,uint16_t key,uint32_t nports,dladm_aggr_port_attr_db_t * ports,uint32_t policy,boolean_t mac_addr_fixed,const uchar_t * mac_addr,aggr_lacp_mode_t lacp_mode,aggr_lacp_timer_t lacp_timer,boolean_t force)6314ac67f02SAnurag S. Maskey i_dladm_aggr_create_sys(dladm_handle_t handle, datalink_id_t linkid,
6324ac67f02SAnurag S. Maskey uint16_t key, uint32_t nports, dladm_aggr_port_attr_db_t *ports,
6334ac67f02SAnurag S. Maskey uint32_t policy, boolean_t mac_addr_fixed, const uchar_t *mac_addr,
634d62bc4baSyz147064 aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer, boolean_t force)
635f595a68aSyz147064 {
636eae72b5bSSebastien Roy int i, len;
637d62bc4baSyz147064 laioc_create_t *iocp = NULL;
638d62bc4baSyz147064 laioc_port_t *ioc_ports;
639f595a68aSyz147064 dladm_status_t status = DLADM_STATUS_OK;
640f595a68aSyz147064
641d62bc4baSyz147064 len = sizeof (*iocp) + nports * sizeof (laioc_port_t);
642f595a68aSyz147064 iocp = malloc(len);
643f595a68aSyz147064 if (iocp == NULL)
644f595a68aSyz147064 return (DLADM_STATUS_NOMEM);
645f595a68aSyz147064
646d62bc4baSyz147064 iocp->lc_key = key;
647d62bc4baSyz147064 iocp->lc_linkid = linkid;
648d62bc4baSyz147064 iocp->lc_nports = nports;
649d62bc4baSyz147064 iocp->lc_policy = policy;
650d62bc4baSyz147064 iocp->lc_lacp_mode = lacp_mode;
651d62bc4baSyz147064 iocp->lc_lacp_timer = lacp_timer;
652d62bc4baSyz147064 ioc_ports = (laioc_port_t *)(iocp + 1);
653d62bc4baSyz147064 iocp->lc_force = force;
654f595a68aSyz147064
655d62bc4baSyz147064 for (i = 0; i < nports; i++)
656d62bc4baSyz147064 ioc_ports[i].lp_linkid = ports[i].lp_linkid;
657f595a68aSyz147064
658d62bc4baSyz147064 if (mac_addr_fixed && !VALID_PORT_MAC(mac_addr)) {
659d62bc4baSyz147064 status = DLADM_STATUS_MACADDRINVAL;
660d62bc4baSyz147064 goto done;
661f595a68aSyz147064 }
662f595a68aSyz147064
663d62bc4baSyz147064 bcopy(mac_addr, iocp->lc_mac, ETHERADDRL);
664d62bc4baSyz147064 iocp->lc_mac_fixed = mac_addr_fixed;
665f595a68aSyz147064
6664ac67f02SAnurag S. Maskey if (i_dladm_aggr_ioctl(handle, LAIOC_CREATE, iocp) < 0)
667d62bc4baSyz147064 status = dladm_errno2status(errno);
668f595a68aSyz147064
669d62bc4baSyz147064 done:
670f595a68aSyz147064 free(iocp);
671f595a68aSyz147064 return (status);
672f595a68aSyz147064 }
673f595a68aSyz147064
674f595a68aSyz147064 /*
675f595a68aSyz147064 * Invoked to bring up a link aggregation group.
676f595a68aSyz147064 */
677f595a68aSyz147064 static int
i_dladm_aggr_up(dladm_handle_t handle,datalink_id_t linkid,void * arg)6784ac67f02SAnurag S. Maskey i_dladm_aggr_up(dladm_handle_t handle, datalink_id_t linkid, void *arg)
679f595a68aSyz147064 {
680d62bc4baSyz147064 dladm_status_t *statusp = (dladm_status_t *)arg;
681d62bc4baSyz147064 dladm_aggr_grp_attr_t attr;
682d62bc4baSyz147064 dladm_aggr_port_attr_db_t *ports = NULL;
683d62bc4baSyz147064 uint16_t key = 0;
684f595a68aSyz147064 int i, j;
685f595a68aSyz147064 dladm_status_t status;
686f595a68aSyz147064
6874ac67f02SAnurag S. Maskey status = dladm_aggr_info(handle, linkid, &attr, DLADM_OPT_PERSIST);
688d62bc4baSyz147064 if (status != DLADM_STATUS_OK) {
689d62bc4baSyz147064 *statusp = status;
690d62bc4baSyz147064 return (DLADM_WALK_CONTINUE);
691d62bc4baSyz147064 }
692f595a68aSyz147064
693d62bc4baSyz147064 if (attr.lg_key <= AGGR_MAX_KEY)
694d62bc4baSyz147064 key = attr.lg_key;
695f595a68aSyz147064
696d62bc4baSyz147064 ports = malloc(attr.lg_nports * sizeof (dladm_aggr_port_attr_db_t));
697d62bc4baSyz147064 if (ports == NULL) {
698d62bc4baSyz147064 status = DLADM_STATUS_NOMEM;
699d62bc4baSyz147064 goto done;
700f595a68aSyz147064 }
701f595a68aSyz147064
702f595a68aSyz147064 /*
703d62bc4baSyz147064 * Validate (and purge) each physical link associated with this
704d62bc4baSyz147064 * aggregation, if the specific hardware has been removed during
705d62bc4baSyz147064 * the system shutdown.
706f595a68aSyz147064 */
707d62bc4baSyz147064 for (i = 0, j = 0; i < attr.lg_nports; i++) {
708d62bc4baSyz147064 datalink_id_t portid = attr.lg_ports[i].lp_linkid;
709d62bc4baSyz147064 uint32_t flags;
710d62bc4baSyz147064 dladm_status_t s;
711f595a68aSyz147064
7124ac67f02SAnurag S. Maskey s = dladm_datalink_id2info(handle, portid, &flags, NULL, NULL,
7134ac67f02SAnurag S. Maskey NULL, 0);
714d62bc4baSyz147064 if (s != DLADM_STATUS_OK || !(flags & DLADM_OPT_ACTIVE))
715d62bc4baSyz147064 continue;
716f595a68aSyz147064
717d62bc4baSyz147064 ports[j++].lp_linkid = portid;
718d62bc4baSyz147064 }
719d62bc4baSyz147064
720d62bc4baSyz147064 if (j == 0) {
721d62bc4baSyz147064 /*
722d62bc4baSyz147064 * All of the physical links are removed.
723d62bc4baSyz147064 */
724d62bc4baSyz147064 status = DLADM_STATUS_BADARG;
725d62bc4baSyz147064 goto done;
726d62bc4baSyz147064 }
727d62bc4baSyz147064
728d62bc4baSyz147064 /*
729d62bc4baSyz147064 * Create active aggregation.
730d62bc4baSyz147064 */
7314ac67f02SAnurag S. Maskey if ((status = i_dladm_aggr_create_sys(handle, linkid,
732d62bc4baSyz147064 key, j, ports, attr.lg_policy, attr.lg_mac_fixed,
733d62bc4baSyz147064 (const uchar_t *)attr.lg_mac, attr.lg_lacp_mode,
734d62bc4baSyz147064 attr.lg_lacp_timer, attr.lg_force)) != DLADM_STATUS_OK) {
735d62bc4baSyz147064 goto done;
736d62bc4baSyz147064 }
737d62bc4baSyz147064
7384ac67f02SAnurag S. Maskey if ((status = dladm_up_datalink_id(handle, linkid)) !=
7394ac67f02SAnurag S. Maskey DLADM_STATUS_OK) {
740d62bc4baSyz147064 laioc_delete_t ioc;
7412b24ab6bSSebastien Roy
742d62bc4baSyz147064 ioc.ld_linkid = linkid;
7434ac67f02SAnurag S. Maskey (void) i_dladm_aggr_ioctl(handle, LAIOC_DELETE, &ioc);
744d62bc4baSyz147064 }
745d62bc4baSyz147064 done:
746d62bc4baSyz147064 free(attr.lg_ports);
747d62bc4baSyz147064 free(ports);
748d62bc4baSyz147064
749d62bc4baSyz147064 *statusp = status;
750d62bc4baSyz147064 return (DLADM_WALK_CONTINUE);
751d62bc4baSyz147064 }
752d62bc4baSyz147064
753d62bc4baSyz147064 /*
754d62bc4baSyz147064 * Bring up one aggregation, or all persistent aggregations. In the latter
755d62bc4baSyz147064 * case, the walk may terminate early if bringup of an aggregation fails.
756d62bc4baSyz147064 */
757d62bc4baSyz147064 dladm_status_t
dladm_aggr_up(dladm_handle_t handle,datalink_id_t linkid)7584ac67f02SAnurag S. Maskey dladm_aggr_up(dladm_handle_t handle, datalink_id_t linkid)
759f595a68aSyz147064 {
760f595a68aSyz147064 dladm_status_t status;
761f595a68aSyz147064
762d62bc4baSyz147064 if (linkid == DATALINK_ALL_LINKID) {
7634ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(i_dladm_aggr_up, handle, &status,
764d62bc4baSyz147064 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE,
765d62bc4baSyz147064 DLADM_OPT_PERSIST);
766f595a68aSyz147064 return (DLADM_STATUS_OK);
767d62bc4baSyz147064 } else {
7684ac67f02SAnurag S. Maskey (void) i_dladm_aggr_up(handle, linkid, &status);
769d62bc4baSyz147064 return (status);
770d62bc4baSyz147064 }
771f595a68aSyz147064 }
772f595a68aSyz147064
773f595a68aSyz147064 /*
774f595a68aSyz147064 * Given a policy string, return a policy mask. Returns B_TRUE on
775d62bc4baSyz147064 * success, or B_FALSE if an error occurred during parsing.
776f595a68aSyz147064 */
777f595a68aSyz147064 boolean_t
dladm_aggr_str2policy(const char * str,uint32_t * policy)778f595a68aSyz147064 dladm_aggr_str2policy(const char *str, uint32_t *policy)
779f595a68aSyz147064 {
780f595a68aSyz147064 int i;
781f595a68aSyz147064 policy_t *pol;
782f595a68aSyz147064 char *token = NULL;
783f595a68aSyz147064 char *lasts;
784f595a68aSyz147064
785f595a68aSyz147064 *policy = 0;
786f595a68aSyz147064
787f595a68aSyz147064 while ((token = strtok_r((token == NULL) ? (char *)str : NULL, ",",
788f595a68aSyz147064 &lasts)) != NULL) {
789f595a68aSyz147064 for (i = 0; i < NPOLICIES; i++) {
790f595a68aSyz147064 pol = &policies[i];
791f595a68aSyz147064 if (strcasecmp(token, pol->pol_name) == 0) {
792f595a68aSyz147064 *policy |= pol->policy;
793f595a68aSyz147064 break;
794f595a68aSyz147064 }
795f595a68aSyz147064 }
796f595a68aSyz147064 if (i == NPOLICIES)
797f595a68aSyz147064 return (B_FALSE);
798f595a68aSyz147064 }
799f595a68aSyz147064
800f595a68aSyz147064 return (B_TRUE);
801f595a68aSyz147064 }
802f595a68aSyz147064
803f595a68aSyz147064 /*
804f595a68aSyz147064 * Given a policy mask, returns a printable string, or NULL if the
805f595a68aSyz147064 * policy mask is invalid. It is the responsibility of the caller to
806f595a68aSyz147064 * free the returned string after use.
807f595a68aSyz147064 */
808f595a68aSyz147064 char *
dladm_aggr_policy2str(uint32_t policy,char * str)809f595a68aSyz147064 dladm_aggr_policy2str(uint32_t policy, char *str)
810f595a68aSyz147064 {
811f595a68aSyz147064 int i, npolicies = 0;
812f595a68aSyz147064 policy_t *pol;
813f595a68aSyz147064
814d62bc4baSyz147064 if (str == NULL)
815d62bc4baSyz147064 return (NULL);
816d62bc4baSyz147064
817f595a68aSyz147064 str[0] = '\0';
818f595a68aSyz147064
819f595a68aSyz147064 for (i = 0; i < NPOLICIES; i++) {
820f595a68aSyz147064 pol = &policies[i];
821f595a68aSyz147064 if ((policy & pol->policy) != 0) {
822f595a68aSyz147064 npolicies++;
823f595a68aSyz147064 if (npolicies > 1)
824d62bc4baSyz147064 (void) strlcat(str, ",", DLADM_STRSIZE);
825d62bc4baSyz147064 (void) strlcat(str, pol->pol_name, DLADM_STRSIZE);
826f595a68aSyz147064 }
827f595a68aSyz147064 }
828f595a68aSyz147064
829f595a68aSyz147064 return (str);
830f595a68aSyz147064 }
831f595a68aSyz147064
832f595a68aSyz147064 /*
833f595a68aSyz147064 * Given a MAC address string, return the MAC address in the mac_addr
834f595a68aSyz147064 * array. If the MAC address was not explicitly specified, i.e. is
835f595a68aSyz147064 * equal to 'auto', zero out mac-addr and set mac_fixed to B_TRUE.
836f595a68aSyz147064 * Return B_FALSE if a syntax error was encountered, B_FALSE otherwise.
837f595a68aSyz147064 */
838f595a68aSyz147064 boolean_t
dladm_aggr_str2macaddr(const char * str,boolean_t * mac_fixed,uchar_t * mac_addr)839f595a68aSyz147064 dladm_aggr_str2macaddr(const char *str, boolean_t *mac_fixed, uchar_t *mac_addr)
840f595a68aSyz147064 {
841f595a68aSyz147064 uchar_t *conv_str;
842f595a68aSyz147064 int mac_len;
843f595a68aSyz147064
844f595a68aSyz147064 *mac_fixed = (strcmp(str, "auto") != 0);
845f595a68aSyz147064 if (!*mac_fixed) {
846f595a68aSyz147064 bzero(mac_addr, ETHERADDRL);
847f595a68aSyz147064 return (B_TRUE);
848f595a68aSyz147064 }
849f595a68aSyz147064
850f595a68aSyz147064 conv_str = _link_aton(str, &mac_len);
851f595a68aSyz147064 if (conv_str == NULL)
852f595a68aSyz147064 return (B_FALSE);
853f595a68aSyz147064
854f595a68aSyz147064 if (mac_len != ETHERADDRL) {
855f595a68aSyz147064 free(conv_str);
856f595a68aSyz147064 return (B_FALSE);
857f595a68aSyz147064 }
858f595a68aSyz147064
859f595a68aSyz147064 if ((bcmp(zero_mac, conv_str, ETHERADDRL) == 0) ||
860f595a68aSyz147064 (conv_str[0] & 0x01)) {
861f595a68aSyz147064 free(conv_str);
862f595a68aSyz147064 return (B_FALSE);
863f595a68aSyz147064 }
864f595a68aSyz147064
865f595a68aSyz147064 bcopy(conv_str, mac_addr, ETHERADDRL);
866f595a68aSyz147064 free(conv_str);
867f595a68aSyz147064
868f595a68aSyz147064 return (B_TRUE);
869f595a68aSyz147064 }
870f595a68aSyz147064
871f595a68aSyz147064 /*
872f595a68aSyz147064 * Returns a string containing a printable representation of a MAC address.
873f595a68aSyz147064 */
874f595a68aSyz147064 const char *
dladm_aggr_macaddr2str(const unsigned char * mac,char * buf)875d62bc4baSyz147064 dladm_aggr_macaddr2str(const unsigned char *mac, char *buf)
876f595a68aSyz147064 {
877f595a68aSyz147064 static char unknown_mac[] = {0, 0, 0, 0, 0, 0};
878f595a68aSyz147064
879f595a68aSyz147064 if (buf == NULL)
880f595a68aSyz147064 return (NULL);
881f595a68aSyz147064
882f595a68aSyz147064 if (bcmp(unknown_mac, mac, ETHERADDRL) == 0)
883d62bc4baSyz147064 (void) strlcpy(buf, "unknown", DLADM_STRSIZE);
884f595a68aSyz147064 else
885f595a68aSyz147064 return (_link_ntoa(mac, buf, ETHERADDRL, IFT_OTHER));
886d62bc4baSyz147064
887d62bc4baSyz147064 return (buf);
888f595a68aSyz147064 }
889f595a68aSyz147064
890f595a68aSyz147064 /*
891f595a68aSyz147064 * Given a LACP mode string, find the corresponding LACP mode number. Returns
892f595a68aSyz147064 * B_TRUE if a match was found, B_FALSE otherwise.
893f595a68aSyz147064 */
894f595a68aSyz147064 boolean_t
dladm_aggr_str2lacpmode(const char * str,aggr_lacp_mode_t * lacp_mode)895f595a68aSyz147064 dladm_aggr_str2lacpmode(const char *str, aggr_lacp_mode_t *lacp_mode)
896f595a68aSyz147064 {
897f595a68aSyz147064 int i;
898f595a68aSyz147064 dladm_aggr_lacpmode_t *mode;
899f595a68aSyz147064
900f595a68aSyz147064 for (i = 0; i < NLACP_MODES; i++) {
901f595a68aSyz147064 mode = &lacp_modes[i];
902f595a68aSyz147064 if (strncasecmp(str, mode->mode_str,
903f595a68aSyz147064 strlen(mode->mode_str)) == 0) {
904f595a68aSyz147064 *lacp_mode = mode->mode_id;
905f595a68aSyz147064 return (B_TRUE);
906f595a68aSyz147064 }
907f595a68aSyz147064 }
908f595a68aSyz147064
909f595a68aSyz147064 return (B_FALSE);
910f595a68aSyz147064 }
911f595a68aSyz147064
912f595a68aSyz147064 /*
913f595a68aSyz147064 * Given a LACP mode number, returns a printable string, or NULL if the
914f595a68aSyz147064 * LACP mode number is invalid.
915f595a68aSyz147064 */
916f595a68aSyz147064 const char *
dladm_aggr_lacpmode2str(aggr_lacp_mode_t mode_id,char * buf)917f595a68aSyz147064 dladm_aggr_lacpmode2str(aggr_lacp_mode_t mode_id, char *buf)
918f595a68aSyz147064 {
919f595a68aSyz147064 int i;
920f595a68aSyz147064 dladm_aggr_lacpmode_t *mode;
921f595a68aSyz147064
922d62bc4baSyz147064 if (buf == NULL)
923d62bc4baSyz147064 return (NULL);
924d62bc4baSyz147064
925f595a68aSyz147064 for (i = 0; i < NLACP_MODES; i++) {
926f595a68aSyz147064 mode = &lacp_modes[i];
927f595a68aSyz147064 if (mode->mode_id == mode_id) {
928f595a68aSyz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s",
929f595a68aSyz147064 mode->mode_str);
930f595a68aSyz147064 return (buf);
931f595a68aSyz147064 }
932f595a68aSyz147064 }
933f595a68aSyz147064
934f595a68aSyz147064 (void) strlcpy(buf, "unknown", DLADM_STRSIZE);
935f595a68aSyz147064 return (buf);
936f595a68aSyz147064 }
937f595a68aSyz147064
938f595a68aSyz147064 /*
939f595a68aSyz147064 * Given a LACP timer string, find the corresponding LACP timer number. Returns
940f595a68aSyz147064 * B_TRUE if a match was found, B_FALSE otherwise.
941f595a68aSyz147064 */
942f595a68aSyz147064 boolean_t
dladm_aggr_str2lacptimer(const char * str,aggr_lacp_timer_t * lacp_timer)943f595a68aSyz147064 dladm_aggr_str2lacptimer(const char *str, aggr_lacp_timer_t *lacp_timer)
944f595a68aSyz147064 {
945f595a68aSyz147064 int i;
946f595a68aSyz147064 dladm_aggr_lacptimer_t *timer;
947f595a68aSyz147064
948f595a68aSyz147064 for (i = 0; i < NLACP_TIMERS; i++) {
949f595a68aSyz147064 timer = &lacp_timers[i];
950f595a68aSyz147064 if (strncasecmp(str, timer->lt_str,
951f595a68aSyz147064 strlen(timer->lt_str)) == 0) {
952f595a68aSyz147064 *lacp_timer = timer->lt_id;
953f595a68aSyz147064 return (B_TRUE);
954f595a68aSyz147064 }
955f595a68aSyz147064 }
956f595a68aSyz147064
957f595a68aSyz147064 return (B_FALSE);
958f595a68aSyz147064 }
959f595a68aSyz147064
960f595a68aSyz147064 /*
961f595a68aSyz147064 * Given a LACP timer, returns a printable string, or NULL if the
962f595a68aSyz147064 * LACP timer number is invalid.
963f595a68aSyz147064 */
964f595a68aSyz147064 const char *
dladm_aggr_lacptimer2str(aggr_lacp_timer_t timer_id,char * buf)965f595a68aSyz147064 dladm_aggr_lacptimer2str(aggr_lacp_timer_t timer_id, char *buf)
966f595a68aSyz147064 {
967f595a68aSyz147064 int i;
968f595a68aSyz147064 dladm_aggr_lacptimer_t *timer;
969f595a68aSyz147064
970d62bc4baSyz147064 if (buf == NULL)
971d62bc4baSyz147064 return (NULL);
972d62bc4baSyz147064
973f595a68aSyz147064 for (i = 0; i < NLACP_TIMERS; i++) {
974f595a68aSyz147064 timer = &lacp_timers[i];
975f595a68aSyz147064 if (timer->lt_id == timer_id) {
976f595a68aSyz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s",
977f595a68aSyz147064 timer->lt_str);
978f595a68aSyz147064 return (buf);
979f595a68aSyz147064 }
980f595a68aSyz147064 }
981f595a68aSyz147064
982f595a68aSyz147064 (void) strlcpy(buf, "unknown", DLADM_STRSIZE);
983f595a68aSyz147064 return (buf);
984f595a68aSyz147064 }
985f595a68aSyz147064
986f595a68aSyz147064 const char *
dladm_aggr_portstate2str(aggr_port_state_t state_id,char * buf)987f595a68aSyz147064 dladm_aggr_portstate2str(aggr_port_state_t state_id, char *buf)
988f595a68aSyz147064 {
989f595a68aSyz147064 int i;
990f595a68aSyz147064 dladm_aggr_port_state_t *state;
991f595a68aSyz147064
992d62bc4baSyz147064 if (buf == NULL)
993d62bc4baSyz147064 return (NULL);
994d62bc4baSyz147064
995f595a68aSyz147064 for (i = 0; i < NPORT_STATES; i++) {
996f595a68aSyz147064 state = &port_states[i];
997f595a68aSyz147064 if (state->state_id == state_id) {
998f595a68aSyz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s",
999f595a68aSyz147064 state->state_str);
1000f595a68aSyz147064 return (buf);
1001f595a68aSyz147064 }
1002f595a68aSyz147064 }
1003f595a68aSyz147064
1004f595a68aSyz147064 (void) strlcpy(buf, "unknown", DLADM_STRSIZE);
1005f595a68aSyz147064 return (buf);
1006f595a68aSyz147064 }
1007f595a68aSyz147064
1008f595a68aSyz147064 static dladm_status_t
dladm_aggr_persist_aggr_conf(dladm_handle_t handle,const char * link,datalink_id_t linkid,uint16_t key,uint32_t nports,dladm_aggr_port_attr_db_t * ports,uint32_t policy,boolean_t mac_addr_fixed,const uchar_t * mac_addr,aggr_lacp_mode_t lacp_mode,aggr_lacp_timer_t lacp_timer,boolean_t force)10094ac67f02SAnurag S. Maskey dladm_aggr_persist_aggr_conf(dladm_handle_t handle, const char *link,
10104ac67f02SAnurag S. Maskey datalink_id_t linkid, uint16_t key, uint32_t nports,
10114ac67f02SAnurag S. Maskey dladm_aggr_port_attr_db_t *ports, uint32_t policy, boolean_t mac_addr_fixed,
10124ac67f02SAnurag S. Maskey const uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode,
10134ac67f02SAnurag S. Maskey aggr_lacp_timer_t lacp_timer, boolean_t force)
1014f595a68aSyz147064 {
1015*32715170SCathy Zhou dladm_conf_t conf;
1016d62bc4baSyz147064 char *portstr = NULL;
1017d62bc4baSyz147064 char macstr[ETHERADDRL * 3];
1018f595a68aSyz147064 dladm_status_t status;
1019d62bc4baSyz147064 int i, size;
1020d62bc4baSyz147064 uint64_t u64;
1021f595a68aSyz147064
10224ac67f02SAnurag S. Maskey if ((status = dladm_create_conf(handle, link, linkid,
10234ac67f02SAnurag S. Maskey DATALINK_CLASS_AGGR, DL_ETHER, &conf)) != DLADM_STATUS_OK) {
1024f595a68aSyz147064 return (status);
1025f595a68aSyz147064 }
1026f595a68aSyz147064
1027d62bc4baSyz147064 u64 = key;
10284ac67f02SAnurag S. Maskey status = dladm_set_conf_field(handle, conf, FKEY, DLADM_TYPE_UINT64,
10294ac67f02SAnurag S. Maskey &u64);
1030d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
1031d62bc4baSyz147064 goto done;
1032f595a68aSyz147064
1033d62bc4baSyz147064 u64 = nports;
10344ac67f02SAnurag S. Maskey status = dladm_set_conf_field(handle, conf, FNPORTS, DLADM_TYPE_UINT64,
10354ac67f02SAnurag S. Maskey &u64);
1036d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
1037d62bc4baSyz147064 goto done;
1038f595a68aSyz147064
10392b24ab6bSSebastien Roy size = nports * MAXLINKNAMELEN + 1;
1040d62bc4baSyz147064 if ((portstr = calloc(1, size)) == NULL) {
1041d62bc4baSyz147064 status = DLADM_STATUS_NOMEM;
1042f595a68aSyz147064 goto done;
1043f595a68aSyz147064 }
1044f595a68aSyz147064
10452b24ab6bSSebastien Roy for (i = 0; i < nports; i++) {
10462b24ab6bSSebastien Roy status = write_port(handle, portstr, ports[i].lp_linkid, size);
10472b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) {
10482b24ab6bSSebastien Roy free(portstr);
10492b24ab6bSSebastien Roy goto done;
10502b24ab6bSSebastien Roy }
10512b24ab6bSSebastien Roy }
10524ac67f02SAnurag S. Maskey status = dladm_set_conf_field(handle, conf, FPORTS, DLADM_TYPE_STR,
10534ac67f02SAnurag S. Maskey portstr);
1054d62bc4baSyz147064 free(portstr);
1055d62bc4baSyz147064
1056d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
1057d62bc4baSyz147064 goto done;
1058d62bc4baSyz147064
1059d62bc4baSyz147064 u64 = policy;
10604ac67f02SAnurag S. Maskey status = dladm_set_conf_field(handle, conf, FPOLICY, DLADM_TYPE_UINT64,
10614ac67f02SAnurag S. Maskey &u64);
1062d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
1063d62bc4baSyz147064 goto done;
1064d62bc4baSyz147064
10654ac67f02SAnurag S. Maskey status = dladm_set_conf_field(handle, conf, FFIXMACADDR,
10664ac67f02SAnurag S. Maskey DLADM_TYPE_BOOLEAN, &mac_addr_fixed);
1067d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
1068d62bc4baSyz147064 goto done;
1069d62bc4baSyz147064
1070d62bc4baSyz147064 if (mac_addr_fixed) {
1071d62bc4baSyz147064 if (!VALID_PORT_MAC(mac_addr)) {
1072d62bc4baSyz147064 status = DLADM_STATUS_MACADDRINVAL;
1073f595a68aSyz147064 goto done;
1074f595a68aSyz147064 }
1075d62bc4baSyz147064
1076d62bc4baSyz147064 (void) dladm_aggr_macaddr2str(mac_addr, macstr);
10774ac67f02SAnurag S. Maskey status = dladm_set_conf_field(handle, conf, FMACADDR,
10784ac67f02SAnurag S. Maskey DLADM_TYPE_STR, macstr);
1079d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
1080d62bc4baSyz147064 goto done;
1081f595a68aSyz147064 }
1082f595a68aSyz147064
10834ac67f02SAnurag S. Maskey status = dladm_set_conf_field(handle, conf, FFORCE, DLADM_TYPE_BOOLEAN,
10844ac67f02SAnurag S. Maskey &force);
1085d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
1086d62bc4baSyz147064 goto done;
1087d62bc4baSyz147064
1088d62bc4baSyz147064 u64 = lacp_mode;
10894ac67f02SAnurag S. Maskey status = dladm_set_conf_field(handle, conf, FLACPMODE,
10904ac67f02SAnurag S. Maskey DLADM_TYPE_UINT64, &u64);
1091d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
1092d62bc4baSyz147064 goto done;
1093d62bc4baSyz147064
1094d62bc4baSyz147064 u64 = lacp_timer;
10954ac67f02SAnurag S. Maskey status = dladm_set_conf_field(handle, conf, FLACPTIMER,
10964ac67f02SAnurag S. Maskey DLADM_TYPE_UINT64, &u64);
1097d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
1098d62bc4baSyz147064 goto done;
1099d62bc4baSyz147064
1100f595a68aSyz147064 /*
1101d62bc4baSyz147064 * Commit the link aggregation configuration.
1102f595a68aSyz147064 */
11034ac67f02SAnurag S. Maskey status = dladm_write_conf(handle, conf);
1104f595a68aSyz147064
1105f595a68aSyz147064 done:
11064ac67f02SAnurag S. Maskey dladm_destroy_conf(handle, conf);
1107f595a68aSyz147064 return (status);
1108f595a68aSyz147064 }
1109f595a68aSyz147064
1110f595a68aSyz147064 /*
1111f595a68aSyz147064 * Create a new link aggregation group. Update the configuration
1112f595a68aSyz147064 * file and bring it up.
1113f595a68aSyz147064 */
1114f595a68aSyz147064 dladm_status_t
dladm_aggr_create(dladm_handle_t handle,const char * name,uint16_t key,uint32_t nports,dladm_aggr_port_attr_db_t * ports,uint32_t policy,boolean_t mac_addr_fixed,const uchar_t * mac_addr,aggr_lacp_mode_t lacp_mode,aggr_lacp_timer_t lacp_timer,uint32_t flags)11154ac67f02SAnurag S. Maskey dladm_aggr_create(dladm_handle_t handle, const char *name, uint16_t key,
11164ac67f02SAnurag S. Maskey uint32_t nports, dladm_aggr_port_attr_db_t *ports, uint32_t policy,
11174ac67f02SAnurag S. Maskey boolean_t mac_addr_fixed, const uchar_t *mac_addr,
11184ac67f02SAnurag S. Maskey aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer, uint32_t flags)
1119f595a68aSyz147064 {
1120d62bc4baSyz147064 datalink_id_t linkid = DATALINK_INVALID_LINKID;
1121d62bc4baSyz147064 uint32_t media;
1122d62bc4baSyz147064 uint32_t i;
1123d62bc4baSyz147064 datalink_class_t class;
1124f595a68aSyz147064 dladm_status_t status;
1125d62bc4baSyz147064 boolean_t force = (flags & DLADM_OPT_FORCE) ? B_TRUE : B_FALSE;
1126f595a68aSyz147064
1127d62bc4baSyz147064 if (key != 0 && key > AGGR_MAX_KEY)
1128f595a68aSyz147064 return (DLADM_STATUS_KEYINVAL);
1129f595a68aSyz147064
1130d62bc4baSyz147064 if (nports == 0)
1131d62bc4baSyz147064 return (DLADM_STATUS_BADARG);
1132f595a68aSyz147064
1133d62bc4baSyz147064 for (i = 0; i < nports; i++) {
11344ac67f02SAnurag S. Maskey if ((dladm_datalink_id2info(handle, ports[i].lp_linkid, NULL,
1135d62bc4baSyz147064 &class, &media, NULL, 0) != DLADM_STATUS_OK) ||
1136b509e89bSRishi Srivatsavai !((class == DATALINK_CLASS_PHYS || class ==
1137b509e89bSRishi Srivatsavai DATALINK_CLASS_SIMNET) && (media == DL_ETHER))) {
1138d62bc4baSyz147064 return (DLADM_STATUS_BADARG);
1139d62bc4baSyz147064 }
1140d62bc4baSyz147064 }
1141f595a68aSyz147064
1142d62bc4baSyz147064 flags &= (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
11434ac67f02SAnurag S. Maskey if ((status = dladm_create_datalink_id(handle, name,
11444ac67f02SAnurag S. Maskey DATALINK_CLASS_AGGR, DL_ETHER, flags, &linkid)) !=
11454ac67f02SAnurag S. Maskey DLADM_STATUS_OK) {
1146d62bc4baSyz147064 goto fail;
1147d62bc4baSyz147064 }
1148f595a68aSyz147064
1149d62bc4baSyz147064 if ((flags & DLADM_OPT_PERSIST) &&
11504ac67f02SAnurag S. Maskey (status = dladm_aggr_persist_aggr_conf(handle, name, linkid, key,
11514ac67f02SAnurag S. Maskey nports, ports, policy, mac_addr_fixed, mac_addr, lacp_mode,
11524ac67f02SAnurag S. Maskey lacp_timer, force)) != DLADM_STATUS_OK) {
1153d62bc4baSyz147064 goto fail;
1154d62bc4baSyz147064 }
1155d62bc4baSyz147064
1156d62bc4baSyz147064 if (!(flags & DLADM_OPT_ACTIVE))
1157d62bc4baSyz147064 return (DLADM_STATUS_OK);
1158d62bc4baSyz147064
11594ac67f02SAnurag S. Maskey status = i_dladm_aggr_create_sys(handle, linkid, key, nports, ports,
11604ac67f02SAnurag S. Maskey policy, mac_addr_fixed, mac_addr, lacp_mode, lacp_timer, force);
1161d62bc4baSyz147064
1162d62bc4baSyz147064 if (status != DLADM_STATUS_OK) {
1163d62bc4baSyz147064 if (flags & DLADM_OPT_PERSIST)
11644ac67f02SAnurag S. Maskey (void) dladm_remove_conf(handle, linkid);
1165d62bc4baSyz147064 goto fail;
1166d62bc4baSyz147064 }
1167d62bc4baSyz147064
1168d62bc4baSyz147064 return (DLADM_STATUS_OK);
1169d62bc4baSyz147064
1170d62bc4baSyz147064 fail:
1171d62bc4baSyz147064 if (linkid != DATALINK_INVALID_LINKID)
11724ac67f02SAnurag S. Maskey (void) dladm_destroy_datalink_id(handle, linkid, flags);
1173d62bc4baSyz147064
1174f595a68aSyz147064 return (status);
1175f595a68aSyz147064 }
1176f595a68aSyz147064
1177d62bc4baSyz147064 static dladm_status_t
i_dladm_aggr_get_aggr_attr(dladm_handle_t handle,dladm_conf_t conf,uint32_t mask,dladm_aggr_modify_attr_t * attrp)11784ac67f02SAnurag S. Maskey i_dladm_aggr_get_aggr_attr(dladm_handle_t handle, dladm_conf_t conf,
11794ac67f02SAnurag S. Maskey uint32_t mask, dladm_aggr_modify_attr_t *attrp)
1180d62bc4baSyz147064 {
1181d62bc4baSyz147064 dladm_status_t status = DLADM_STATUS_OK;
1182d62bc4baSyz147064 char macstr[ETHERADDRL * 3];
1183d62bc4baSyz147064 uint64_t u64;
1184f595a68aSyz147064
1185d62bc4baSyz147064 if (mask & DLADM_AGGR_MODIFY_POLICY) {
11864ac67f02SAnurag S. Maskey status = dladm_get_conf_field(handle, conf, FPOLICY, &u64,
1187d62bc4baSyz147064 sizeof (u64));
1188d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
1189d62bc4baSyz147064 return (status);
1190d62bc4baSyz147064 attrp->ld_policy = (uint32_t)u64;
1191d62bc4baSyz147064 }
1192d62bc4baSyz147064
1193d62bc4baSyz147064 if (mask & DLADM_AGGR_MODIFY_MAC) {
11944ac67f02SAnurag S. Maskey status = dladm_get_conf_field(handle, conf, FFIXMACADDR,
1195d62bc4baSyz147064 &attrp->ld_mac_fixed, sizeof (boolean_t));
1196d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
1197d62bc4baSyz147064 return (status);
1198d62bc4baSyz147064
1199d62bc4baSyz147064 if (attrp->ld_mac_fixed) {
1200d62bc4baSyz147064 boolean_t fixed;
1201d62bc4baSyz147064
12024ac67f02SAnurag S. Maskey status = dladm_get_conf_field(handle, conf, FMACADDR,
1203d62bc4baSyz147064 macstr, sizeof (macstr));
1204d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
1205d62bc4baSyz147064 return (status);
1206d62bc4baSyz147064
1207d62bc4baSyz147064 if (!dladm_aggr_str2macaddr(macstr, &fixed,
1208d62bc4baSyz147064 attrp->ld_mac)) {
1209d62bc4baSyz147064 return (DLADM_STATUS_REPOSITORYINVAL);
1210d62bc4baSyz147064 }
1211d62bc4baSyz147064 }
1212d62bc4baSyz147064 }
1213d62bc4baSyz147064
1214d62bc4baSyz147064 if (mask & DLADM_AGGR_MODIFY_LACP_MODE) {
12154ac67f02SAnurag S. Maskey status = dladm_get_conf_field(handle, conf, FLACPMODE, &u64,
1216d62bc4baSyz147064 sizeof (u64));
1217d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
1218d62bc4baSyz147064 return (status);
1219d62bc4baSyz147064 attrp->ld_lacp_mode = (aggr_lacp_mode_t)u64;
1220d62bc4baSyz147064 }
1221d62bc4baSyz147064
1222d62bc4baSyz147064 if (mask & DLADM_AGGR_MODIFY_LACP_TIMER) {
12234ac67f02SAnurag S. Maskey status = dladm_get_conf_field(handle, conf, FLACPTIMER, &u64,
1224d62bc4baSyz147064 sizeof (u64));
1225d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
1226d62bc4baSyz147064 return (status);
1227d62bc4baSyz147064 attrp->ld_lacp_timer = (aggr_lacp_timer_t)u64;
1228d62bc4baSyz147064 }
1229d62bc4baSyz147064
1230d62bc4baSyz147064 return (status);
1231d62bc4baSyz147064 }
1232d62bc4baSyz147064
1233d62bc4baSyz147064 static dladm_status_t
i_dladm_aggr_set_aggr_attr(dladm_handle_t handle,dladm_conf_t conf,uint32_t mask,dladm_aggr_modify_attr_t * attrp)12344ac67f02SAnurag S. Maskey i_dladm_aggr_set_aggr_attr(dladm_handle_t handle, dladm_conf_t conf,
12354ac67f02SAnurag S. Maskey uint32_t mask, dladm_aggr_modify_attr_t *attrp)
1236d62bc4baSyz147064 {
1237d62bc4baSyz147064 dladm_status_t status = DLADM_STATUS_OK;
1238d62bc4baSyz147064 char macstr[ETHERADDRL * 3];
1239d62bc4baSyz147064 uint64_t u64;
1240d62bc4baSyz147064
1241d62bc4baSyz147064 if (mask & DLADM_AGGR_MODIFY_POLICY) {
1242d62bc4baSyz147064 u64 = attrp->ld_policy;
12434ac67f02SAnurag S. Maskey status = dladm_set_conf_field(handle, conf, FPOLICY,
12444ac67f02SAnurag S. Maskey DLADM_TYPE_UINT64, &u64);
1245d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
1246d62bc4baSyz147064 return (status);
1247d62bc4baSyz147064 }
1248d62bc4baSyz147064
1249d62bc4baSyz147064 if (mask & DLADM_AGGR_MODIFY_MAC) {
12504ac67f02SAnurag S. Maskey status = dladm_set_conf_field(handle, conf, FFIXMACADDR,
1251d62bc4baSyz147064 DLADM_TYPE_BOOLEAN, &attrp->ld_mac_fixed);
1252d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
1253d62bc4baSyz147064 return (status);
1254d62bc4baSyz147064
1255d62bc4baSyz147064 if (attrp->ld_mac_fixed) {
1256d62bc4baSyz147064 (void) dladm_aggr_macaddr2str(attrp->ld_mac, macstr);
12574ac67f02SAnurag S. Maskey status = dladm_set_conf_field(handle, conf, FMACADDR,
1258d62bc4baSyz147064 DLADM_TYPE_STR, macstr);
1259d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
1260d62bc4baSyz147064 return (status);
1261d62bc4baSyz147064 }
1262d62bc4baSyz147064 }
1263d62bc4baSyz147064
1264d62bc4baSyz147064 if (mask & DLADM_AGGR_MODIFY_LACP_MODE) {
1265d62bc4baSyz147064 u64 = attrp->ld_lacp_mode;
12664ac67f02SAnurag S. Maskey status = dladm_set_conf_field(handle, conf, FLACPMODE,
1267d62bc4baSyz147064 DLADM_TYPE_UINT64, &u64);
1268d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
1269d62bc4baSyz147064 return (status);
1270d62bc4baSyz147064 }
1271d62bc4baSyz147064
1272d62bc4baSyz147064 if (mask & DLADM_AGGR_MODIFY_LACP_TIMER) {
1273d62bc4baSyz147064 u64 = attrp->ld_lacp_timer;
12744ac67f02SAnurag S. Maskey status = dladm_set_conf_field(handle, conf, FLACPTIMER,
1275d62bc4baSyz147064 DLADM_TYPE_UINT64, &u64);
1276d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
1277d62bc4baSyz147064 return (status);
1278d62bc4baSyz147064 }
1279f595a68aSyz147064
1280f595a68aSyz147064 return (status);
1281f595a68aSyz147064 }
1282f595a68aSyz147064
1283f595a68aSyz147064 /*
1284f595a68aSyz147064 * Modify the parameters of an existing link aggregation group. Update
1285f595a68aSyz147064 * the configuration file and pass the changes to the kernel.
1286f595a68aSyz147064 */
1287f595a68aSyz147064 dladm_status_t
dladm_aggr_modify(dladm_handle_t handle,datalink_id_t linkid,uint32_t modify_mask,uint32_t policy,boolean_t mac_fixed,const uchar_t * mac_addr,aggr_lacp_mode_t lacp_mode,aggr_lacp_timer_t lacp_timer,uint32_t flags)12884ac67f02SAnurag S. Maskey dladm_aggr_modify(dladm_handle_t handle, datalink_id_t linkid,
12894ac67f02SAnurag S. Maskey uint32_t modify_mask, uint32_t policy, boolean_t mac_fixed,
12904ac67f02SAnurag S. Maskey const uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode,
1291d62bc4baSyz147064 aggr_lacp_timer_t lacp_timer, uint32_t flags)
1292f595a68aSyz147064 {
1293f595a68aSyz147064 dladm_aggr_modify_attr_t new_attr, old_attr;
1294d62bc4baSyz147064 dladm_conf_t conf;
1295f595a68aSyz147064 dladm_status_t status;
1296f595a68aSyz147064
1297f595a68aSyz147064 new_attr.ld_policy = policy;
1298f595a68aSyz147064 new_attr.ld_mac_fixed = mac_fixed;
1299f595a68aSyz147064 new_attr.ld_lacp_mode = lacp_mode;
1300f595a68aSyz147064 new_attr.ld_lacp_timer = lacp_timer;
1301d62bc4baSyz147064 bcopy(mac_addr, new_attr.ld_mac, ETHERADDRL);
1302f595a68aSyz147064
1303d62bc4baSyz147064 if (flags & DLADM_OPT_PERSIST) {
1304*32715170SCathy Zhou status = dladm_open_conf(handle, linkid, &conf);
1305d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
1306d62bc4baSyz147064 return (status);
1307d62bc4baSyz147064
13084ac67f02SAnurag S. Maskey if ((status = i_dladm_aggr_get_aggr_attr(handle, conf,
13094ac67f02SAnurag S. Maskey modify_mask, &old_attr)) != DLADM_STATUS_OK) {
1310d62bc4baSyz147064 goto done;
1311d62bc4baSyz147064 }
1312d62bc4baSyz147064
13134ac67f02SAnurag S. Maskey if ((status = i_dladm_aggr_set_aggr_attr(handle, conf,
13144ac67f02SAnurag S. Maskey modify_mask, &new_attr)) != DLADM_STATUS_OK) {
1315d62bc4baSyz147064 goto done;
1316d62bc4baSyz147064 }
1317d62bc4baSyz147064
13184ac67f02SAnurag S. Maskey status = dladm_write_conf(handle, conf);
1319d62bc4baSyz147064
1320d62bc4baSyz147064 done:
13214ac67f02SAnurag S. Maskey dladm_destroy_conf(handle, conf);
1322d62bc4baSyz147064 if (status != DLADM_STATUS_OK)
1323f595a68aSyz147064 return (status);
1324f595a68aSyz147064 }
1325f595a68aSyz147064
1326d62bc4baSyz147064 if (!(flags & DLADM_OPT_ACTIVE))
1327d62bc4baSyz147064 return (DLADM_STATUS_OK);
1328d62bc4baSyz147064
13294ac67f02SAnurag S. Maskey status = i_dladm_aggr_modify_sys(handle, linkid, modify_mask,
13304ac67f02SAnurag S. Maskey &new_attr);
1331d62bc4baSyz147064 if ((status != DLADM_STATUS_OK) && (flags & DLADM_OPT_PERSIST)) {
1332*32715170SCathy Zhou if (dladm_open_conf(handle, linkid, &conf) == DLADM_STATUS_OK) {
13334ac67f02SAnurag S. Maskey if (i_dladm_aggr_set_aggr_attr(handle, conf,
13344ac67f02SAnurag S. Maskey modify_mask, &old_attr) == DLADM_STATUS_OK) {
13354ac67f02SAnurag S. Maskey (void) dladm_write_conf(handle, conf);
1336d62bc4baSyz147064 }
13374ac67f02SAnurag S. Maskey dladm_destroy_conf(handle, conf);
1338d62bc4baSyz147064 }
1339f595a68aSyz147064 }
1340f595a68aSyz147064
1341f595a68aSyz147064 return (status);
1342f595a68aSyz147064 }
1343f595a68aSyz147064
1344d62bc4baSyz147064 typedef struct aggr_held_arg_s {
1345d62bc4baSyz147064 datalink_id_t aggrid;
1346d62bc4baSyz147064 boolean_t isheld;
1347d62bc4baSyz147064 } aggr_held_arg_t;
1348d62bc4baSyz147064
1349d62bc4baSyz147064 static int
i_dladm_aggr_is_held(dladm_handle_t handle,datalink_id_t linkid,void * arg)13504ac67f02SAnurag S. Maskey i_dladm_aggr_is_held(dladm_handle_t handle, datalink_id_t linkid, void *arg)
1351d62bc4baSyz147064 {
1352d62bc4baSyz147064 aggr_held_arg_t *aggr_held_arg = arg;
1353d62bc4baSyz147064 dladm_vlan_attr_t dva;
1354d62bc4baSyz147064
13554ac67f02SAnurag S. Maskey if (dladm_vlan_info(handle, linkid, &dva, DLADM_OPT_PERSIST) !=
13564ac67f02SAnurag S. Maskey DLADM_STATUS_OK)
1357d62bc4baSyz147064 return (DLADM_WALK_CONTINUE);
1358d62bc4baSyz147064
1359d62bc4baSyz147064 if (dva.dv_linkid == aggr_held_arg->aggrid) {
1360d62bc4baSyz147064 /*
1361d62bc4baSyz147064 * This VLAN is created over the given aggregation.
1362d62bc4baSyz147064 */
1363d62bc4baSyz147064 aggr_held_arg->isheld = B_TRUE;
1364d62bc4baSyz147064 return (DLADM_WALK_TERMINATE);
1365d62bc4baSyz147064 }
1366d62bc4baSyz147064 return (DLADM_WALK_CONTINUE);
1367d62bc4baSyz147064 }
1368d62bc4baSyz147064
1369f595a68aSyz147064 /*
1370d62bc4baSyz147064 * Delete a previously created link aggregation group. Either the name "aggr"
1371d62bc4baSyz147064 * or the "key" is specified.
1372f595a68aSyz147064 */
1373f595a68aSyz147064 dladm_status_t
dladm_aggr_delete(dladm_handle_t handle,datalink_id_t linkid,uint32_t flags)13744ac67f02SAnurag S. Maskey dladm_aggr_delete(dladm_handle_t handle, datalink_id_t linkid, uint32_t flags)
1375f595a68aSyz147064 {
1376d62bc4baSyz147064 laioc_delete_t ioc;
1377d62bc4baSyz147064 datalink_class_t class;
1378f595a68aSyz147064 dladm_status_t status;
1379f595a68aSyz147064
13804ac67f02SAnurag S. Maskey if ((dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, NULL,
13814ac67f02SAnurag S. Maskey 0) != DLADM_STATUS_OK) || (class != DATALINK_CLASS_AGGR)) {
1382d62bc4baSyz147064 return (DLADM_STATUS_BADARG);
1383d62bc4baSyz147064 }
1384f595a68aSyz147064
1385d62bc4baSyz147064 if (flags & DLADM_OPT_ACTIVE) {
1386d62bc4baSyz147064 ioc.ld_linkid = linkid;
13874ac67f02SAnurag S. Maskey if ((i_dladm_aggr_ioctl(handle, LAIOC_DELETE, &ioc) < 0) &&
1388d62bc4baSyz147064 ((errno != ENOENT) || !(flags & DLADM_OPT_PERSIST))) {
1389d62bc4baSyz147064 status = dladm_errno2status(errno);
1390f595a68aSyz147064 return (status);
1391f595a68aSyz147064 }
1392d62bc4baSyz147064
1393d62bc4baSyz147064 /*
1394d62bc4baSyz147064 * Delete ACTIVE linkprop first.
1395d62bc4baSyz147064 */
13964ac67f02SAnurag S. Maskey (void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0,
1397d62bc4baSyz147064 DLADM_OPT_ACTIVE);
13984ac67f02SAnurag S. Maskey (void) dladm_destroy_datalink_id(handle, linkid,
13994ac67f02SAnurag S. Maskey DLADM_OPT_ACTIVE);
1400f595a68aSyz147064 }
1401f595a68aSyz147064
1402d62bc4baSyz147064 /*
1403d62bc4baSyz147064 * If we reach here, it means that the active aggregation has already
1404d62bc4baSyz147064 * been deleted, and there is no active VLANs holding this aggregation.
1405d62bc4baSyz147064 * Now we see whether there is any persistent VLANs holding this
1406d62bc4baSyz147064 * aggregation. If so, we fail the operation.
1407d62bc4baSyz147064 */
1408d62bc4baSyz147064 if (flags & DLADM_OPT_PERSIST) {
1409d62bc4baSyz147064 aggr_held_arg_t arg;
1410f595a68aSyz147064
1411d62bc4baSyz147064 arg.aggrid = linkid;
1412d62bc4baSyz147064 arg.isheld = B_FALSE;
1413d62bc4baSyz147064
14144ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(i_dladm_aggr_is_held, handle,
1415d62bc4baSyz147064 &arg, DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE,
1416d62bc4baSyz147064 DLADM_OPT_PERSIST);
1417d62bc4baSyz147064 if (arg.isheld)
1418d62bc4baSyz147064 return (DLADM_STATUS_LINKBUSY);
1419d62bc4baSyz147064
14202b24ab6bSSebastien Roy (void) dladm_remove_conf(handle, linkid);
14214ac67f02SAnurag S. Maskey (void) dladm_destroy_datalink_id(handle, linkid,
14224ac67f02SAnurag S. Maskey DLADM_OPT_PERSIST);
1423d62bc4baSyz147064 }
1424d62bc4baSyz147064
1425d62bc4baSyz147064 return (DLADM_STATUS_OK);
1426f595a68aSyz147064 }
1427f595a68aSyz147064
1428f595a68aSyz147064 /*
1429f595a68aSyz147064 * Add one or more ports to an existing link aggregation.
1430f595a68aSyz147064 */
1431f595a68aSyz147064 dladm_status_t
dladm_aggr_add(dladm_handle_t handle,datalink_id_t linkid,uint32_t nports,dladm_aggr_port_attr_db_t * ports,uint32_t flags)14324ac67f02SAnurag S. Maskey dladm_aggr_add(dladm_handle_t handle, datalink_id_t linkid, uint32_t nports,
1433d62bc4baSyz147064 dladm_aggr_port_attr_db_t *ports, uint32_t flags)
1434f595a68aSyz147064 {
14354ac67f02SAnurag S. Maskey return (i_dladm_aggr_add_rmv(handle, linkid, nports, ports, flags,
14364ac67f02SAnurag S. Maskey LAIOC_ADD));
1437f595a68aSyz147064 }
1438f595a68aSyz147064
1439f595a68aSyz147064 /*
1440f595a68aSyz147064 * Remove one or more ports from an existing link aggregation.
1441f595a68aSyz147064 */
1442f595a68aSyz147064 dladm_status_t
dladm_aggr_remove(dladm_handle_t handle,datalink_id_t linkid,uint32_t nports,dladm_aggr_port_attr_db_t * ports,uint32_t flags)14434ac67f02SAnurag S. Maskey dladm_aggr_remove(dladm_handle_t handle, datalink_id_t linkid, uint32_t nports,
1444d62bc4baSyz147064 dladm_aggr_port_attr_db_t *ports, uint32_t flags)
1445f595a68aSyz147064 {
14464ac67f02SAnurag S. Maskey return (i_dladm_aggr_add_rmv(handle, linkid, nports, ports, flags,
1447d62bc4baSyz147064 LAIOC_REMOVE));
1448f595a68aSyz147064 }
1449f595a68aSyz147064
1450d62bc4baSyz147064 typedef struct i_walk_key_state_s {
1451d62bc4baSyz147064 uint16_t key;
1452d62bc4baSyz147064 datalink_id_t linkid;
1453d62bc4baSyz147064 boolean_t found;
1454d62bc4baSyz147064 } i_walk_key_state_t;
1455f595a68aSyz147064
1456d62bc4baSyz147064 static int
i_dladm_walk_key2linkid(dladm_handle_t handle,datalink_id_t linkid,void * arg)14574ac67f02SAnurag S. Maskey i_dladm_walk_key2linkid(dladm_handle_t handle, datalink_id_t linkid, void *arg)
1458d62bc4baSyz147064 {
1459d62bc4baSyz147064 dladm_conf_t conf;
1460d62bc4baSyz147064 uint16_t key;
1461d62bc4baSyz147064 dladm_status_t status;
1462d62bc4baSyz147064 i_walk_key_state_t *statep = (i_walk_key_state_t *)arg;
1463d62bc4baSyz147064 uint64_t u64;
1464d62bc4baSyz147064
1465*32715170SCathy Zhou if (dladm_getsnap_conf(handle, linkid, &conf) != DLADM_STATUS_OK)
1466d62bc4baSyz147064 return (DLADM_WALK_CONTINUE);
1467d62bc4baSyz147064
14684ac67f02SAnurag S. Maskey status = dladm_get_conf_field(handle, conf, FKEY, &u64, sizeof (u64));
1469d62bc4baSyz147064 key = (uint16_t)u64;
14704ac67f02SAnurag S. Maskey dladm_destroy_conf(handle, conf);
1471d62bc4baSyz147064
1472d62bc4baSyz147064 if ((status == DLADM_STATUS_OK) && (key == statep->key)) {
1473d62bc4baSyz147064 statep->found = B_TRUE;
1474d62bc4baSyz147064 statep->linkid = linkid;
1475d62bc4baSyz147064 return (DLADM_WALK_TERMINATE);
1476d62bc4baSyz147064 }
1477d62bc4baSyz147064
1478d62bc4baSyz147064 return (DLADM_WALK_CONTINUE);
1479d62bc4baSyz147064 }
1480d62bc4baSyz147064
1481d62bc4baSyz147064 dladm_status_t
dladm_key2linkid(dladm_handle_t handle,uint16_t key,datalink_id_t * linkidp,uint32_t flags)14824ac67f02SAnurag S. Maskey dladm_key2linkid(dladm_handle_t handle, uint16_t key, datalink_id_t *linkidp,
14834ac67f02SAnurag S. Maskey uint32_t flags)
1484d62bc4baSyz147064 {
1485d62bc4baSyz147064 i_walk_key_state_t state;
1486d62bc4baSyz147064
1487d62bc4baSyz147064 if (key > AGGR_MAX_KEY)
1488d62bc4baSyz147064 return (DLADM_STATUS_NOTFOUND);
1489d62bc4baSyz147064
1490d62bc4baSyz147064 state.found = B_FALSE;
1491d62bc4baSyz147064 state.key = key;
1492d62bc4baSyz147064
14934ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(i_dladm_walk_key2linkid, handle, &state,
1494d62bc4baSyz147064 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags);
1495d62bc4baSyz147064 if (state.found == B_TRUE) {
1496d62bc4baSyz147064 *linkidp = state.linkid;
1497d62bc4baSyz147064 return (DLADM_STATUS_OK);
1498d62bc4baSyz147064 } else {
1499d62bc4baSyz147064 return (DLADM_STATUS_NOTFOUND);
1500d62bc4baSyz147064 }
1501f595a68aSyz147064 }
1502