Merge commit '12014b724f98604d61f9756b7e199416475d7396' into merges
[unleashed.git] / usr / src / uts / common / io / aggr / aggr_ctl.c
blob1bbad3d90402a84d94684c1b80099cfa23b5ce2e
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * IEEE 802.3ad Link Aggregation -- IOCTL processing.
30 #include <sys/aggr.h>
31 #include <sys/aggr_impl.h>
32 #include <sys/policy.h>
35 * Process a LAIOC_MODIFY request.
37 /* ARGSUSED */
38 static int
39 aggr_ioc_modify(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
41 laioc_modify_t *modify_arg = karg;
42 uint32_t policy;
43 boolean_t mac_fixed;
44 uchar_t mac_addr[ETHERADDRL];
45 uint8_t modify_mask_arg, modify_mask = 0;
46 aggr_lacp_mode_t lacp_mode;
47 aggr_lacp_timer_t lacp_timer;
49 modify_mask_arg = modify_arg->lu_modify_mask;
51 if (modify_mask_arg & LAIOC_MODIFY_POLICY) {
52 modify_mask |= AGGR_MODIFY_POLICY;
53 policy = modify_arg->lu_policy;
56 if (modify_mask_arg & LAIOC_MODIFY_MAC) {
57 modify_mask |= AGGR_MODIFY_MAC;
58 bcopy(modify_arg->lu_mac, mac_addr, ETHERADDRL);
59 mac_fixed = modify_arg->lu_mac_fixed;
62 if (modify_mask_arg & LAIOC_MODIFY_LACP_MODE) {
63 modify_mask |= AGGR_MODIFY_LACP_MODE;
64 lacp_mode = modify_arg->lu_lacp_mode;
67 if (modify_mask_arg & LAIOC_MODIFY_LACP_TIMER) {
68 modify_mask |= AGGR_MODIFY_LACP_TIMER;
69 lacp_timer = modify_arg->lu_lacp_timer;
72 return (aggr_grp_modify(modify_arg->lu_linkid, modify_mask, policy,
73 mac_fixed, mac_addr, lacp_mode, lacp_timer));
77 * Process a LAIOC_CREATE request.
79 /* ARGSUSED */
80 static int
81 aggr_ioc_create(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
83 laioc_create_t *create_arg = karg;
84 uint16_t nports;
85 laioc_port_t *ports = NULL;
86 size_t ports_size;
87 uint32_t policy;
88 boolean_t mac_fixed;
89 boolean_t force;
90 uchar_t mac_addr[ETHERADDRL];
91 aggr_lacp_mode_t lacp_mode;
92 aggr_lacp_timer_t lacp_timer;
93 int rc;
95 nports = create_arg->lc_nports;
96 if (nports > AGGR_MAX_PORTS)
97 return (EINVAL);
99 policy = create_arg->lc_policy;
100 lacp_mode = create_arg->lc_lacp_mode;
101 lacp_timer = create_arg->lc_lacp_timer;
103 ports_size = nports * sizeof (laioc_port_t);
104 ports = kmem_alloc(ports_size, KM_SLEEP);
106 if (ddi_copyin((uchar_t *)arg + sizeof (*create_arg), ports,
107 ports_size, mode) != 0) {
108 rc = EFAULT;
109 goto done;
112 bcopy(create_arg->lc_mac, mac_addr, ETHERADDRL);
113 mac_fixed = create_arg->lc_mac_fixed;
114 force = create_arg->lc_force;
116 rc = aggr_grp_create(create_arg->lc_linkid, create_arg->lc_key, nports,
117 ports, policy, mac_fixed, force, mac_addr, lacp_mode, lacp_timer,
118 cred);
120 done:
121 kmem_free(ports, ports_size);
122 return (rc);
125 /* ARGSUSED */
126 static int
127 aggr_ioc_delete(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
129 laioc_delete_t *delete_arg = karg;
131 return (aggr_grp_delete(delete_arg->ld_linkid, cred));
134 typedef struct aggr_ioc_info_state {
135 uint32_t bytes_left;
136 uchar_t *where; /* in user buffer */
137 int mode;
138 } aggr_ioc_info_state_t;
140 static int
141 aggr_ioc_info_new_grp(void *arg, datalink_id_t linkid, uint32_t key,
142 uchar_t *mac, boolean_t mac_fixed, boolean_t force, uint32_t policy,
143 uint32_t nports, aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer)
145 aggr_ioc_info_state_t *state = arg;
146 laioc_info_group_t grp;
148 if (state->bytes_left < sizeof (grp))
149 return (ENOSPC);
151 grp.lg_linkid = linkid;
152 grp.lg_key = key;
153 bcopy(mac, grp.lg_mac, ETHERADDRL);
154 grp.lg_mac_fixed = mac_fixed;
155 grp.lg_force = force;
156 grp.lg_policy = policy;
157 grp.lg_nports = nports;
158 grp.lg_lacp_mode = lacp_mode;
159 grp.lg_lacp_timer = lacp_timer;
161 if (ddi_copyout(&grp, state->where, sizeof (grp), state->mode) != 0)
162 return (EFAULT);
164 state->where += sizeof (grp);
165 state->bytes_left -= sizeof (grp);
167 return (0);
170 static int
171 aggr_ioc_info_new_port(void *arg, datalink_id_t linkid, uchar_t *mac,
172 aggr_port_state_t portstate, aggr_lacp_state_t *lacp_state)
174 aggr_ioc_info_state_t *state = arg;
175 laioc_info_port_t port;
177 if (state->bytes_left < sizeof (port))
178 return (ENOSPC);
180 port.lp_linkid = linkid;
181 bcopy(mac, port.lp_mac, ETHERADDRL);
182 port.lp_state = portstate;
183 port.lp_lacp_state = *lacp_state;
185 if (ddi_copyout(&port, state->where, sizeof (port), state->mode) != 0)
186 return (EFAULT);
188 state->where += sizeof (port);
189 state->bytes_left -= sizeof (port);
191 return (0);
194 /*ARGSUSED*/
195 static int
196 aggr_ioc_info(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
198 laioc_info_t *info_argp = karg;
199 aggr_ioc_info_state_t state;
201 state.bytes_left = info_argp->li_bufsize - sizeof (laioc_info_t);
202 state.where = (uchar_t *)arg + sizeof (laioc_info_t);
203 state.mode = mode;
205 return (aggr_grp_info(info_argp->li_group_linkid, &state,
206 aggr_ioc_info_new_grp, aggr_ioc_info_new_port, cred));
209 static int
210 aggr_ioc_add_remove(laioc_add_rem_t *add_rem_arg, intptr_t arg, int cmd,
211 int mode)
213 uint16_t nports;
214 laioc_port_t *ports = NULL;
215 size_t ports_size;
216 int rc;
218 nports = add_rem_arg->la_nports;
219 if (nports > AGGR_MAX_PORTS)
220 return (EINVAL);
222 ports_size = nports * sizeof (laioc_port_t);
223 ports = kmem_alloc(ports_size, KM_SLEEP);
224 if (ddi_copyin((uchar_t *)arg + sizeof (*add_rem_arg), ports,
225 ports_size, mode) != 0) {
226 rc = EFAULT;
227 goto done;
230 switch (cmd) {
231 case LAIOC_ADD:
232 rc = aggr_grp_add_ports(add_rem_arg->la_linkid, nports,
233 add_rem_arg->la_force, ports);
234 break;
235 case LAIOC_REMOVE:
236 rc = aggr_grp_rem_ports(add_rem_arg->la_linkid, nports, ports);
237 break;
240 done:
241 kmem_free(ports, ports_size);
242 return (rc);
245 /* ARGSUSED */
246 static int
247 aggr_ioc_add(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
249 return (aggr_ioc_add_remove(karg, arg, LAIOC_ADD, mode));
252 /* ARGSUSED */
253 static int
254 aggr_ioc_remove(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
256 return (aggr_ioc_add_remove(karg, arg, LAIOC_REMOVE, mode));
259 static dld_ioc_info_t aggr_ioc_list[] = {
260 {LAIOC_CREATE, DLDCOPYIN, sizeof (laioc_create_t), aggr_ioc_create,
261 secpolicy_dl_config},
262 {LAIOC_DELETE, DLDCOPYIN, sizeof (laioc_delete_t), aggr_ioc_delete,
263 secpolicy_dl_config},
264 {LAIOC_INFO, DLDCOPYINOUT, sizeof (laioc_info_t), aggr_ioc_info, NULL},
265 {LAIOC_ADD, DLDCOPYIN, sizeof (laioc_add_rem_t), aggr_ioc_add,
266 secpolicy_dl_config},
267 {LAIOC_REMOVE, DLDCOPYIN, sizeof (laioc_add_rem_t), aggr_ioc_remove,
268 secpolicy_dl_config},
269 {LAIOC_MODIFY, DLDCOPYIN, sizeof (laioc_modify_t), aggr_ioc_modify,
270 secpolicy_dl_config}
274 aggr_ioc_init(void)
276 return (dld_ioc_register(AGGR_IOC, aggr_ioc_list,
277 DLDIOCCNT(aggr_ioc_list)));
280 void
281 aggr_ioc_fini(void)
283 dld_ioc_unregister(AGGR_IOC);