xref: /illumos-gate/usr/src/uts/common/io/aggr/aggr_ctl.c (revision da14cebe)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5ba2e4443Sseb  * Common Development and Distribution License (the "License").
6ba2e4443Sseb  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22d62bc4baSyz  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * IEEE 802.3ad Link Aggregation -- IOCTL processing.
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include <sys/aggr.h>
317c478bd9Sstevel@tonic-gate #include <sys/aggr_impl.h>
32*da14cebeSEric Cheng #include <sys/priv_names.h>
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate /*
357c478bd9Sstevel@tonic-gate  * Process a LAIOC_MODIFY request.
367c478bd9Sstevel@tonic-gate  */
37eae72b5bSSebastien Roy /* ARGSUSED */
387c478bd9Sstevel@tonic-gate static int
39*da14cebeSEric Cheng aggr_ioc_modify(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
407c478bd9Sstevel@tonic-gate {
41eae72b5bSSebastien Roy 	laioc_modify_t *modify_arg = karg;
427c478bd9Sstevel@tonic-gate 	uint32_t policy;
437c478bd9Sstevel@tonic-gate 	boolean_t mac_fixed;
447c478bd9Sstevel@tonic-gate 	uchar_t mac_addr[ETHERADDRL];
457c478bd9Sstevel@tonic-gate 	uint8_t modify_mask_arg, modify_mask = 0;
467c478bd9Sstevel@tonic-gate 	aggr_lacp_mode_t lacp_mode;
477c478bd9Sstevel@tonic-gate 	aggr_lacp_timer_t lacp_timer;
487c478bd9Sstevel@tonic-gate 
49eae72b5bSSebastien Roy 	modify_mask_arg = modify_arg->lu_modify_mask;
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate 	if (modify_mask_arg & LAIOC_MODIFY_POLICY) {
527c478bd9Sstevel@tonic-gate 		modify_mask |= AGGR_MODIFY_POLICY;
53eae72b5bSSebastien Roy 		policy = modify_arg->lu_policy;
547c478bd9Sstevel@tonic-gate 	}
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate 	if (modify_mask_arg & LAIOC_MODIFY_MAC) {
577c478bd9Sstevel@tonic-gate 		modify_mask |= AGGR_MODIFY_MAC;
58eae72b5bSSebastien Roy 		bcopy(modify_arg->lu_mac, mac_addr, ETHERADDRL);
59eae72b5bSSebastien Roy 		mac_fixed = modify_arg->lu_mac_fixed;
607c478bd9Sstevel@tonic-gate 	}
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate 	if (modify_mask_arg & LAIOC_MODIFY_LACP_MODE) {
637c478bd9Sstevel@tonic-gate 		modify_mask |= AGGR_MODIFY_LACP_MODE;
64eae72b5bSSebastien Roy 		lacp_mode = modify_arg->lu_lacp_mode;
657c478bd9Sstevel@tonic-gate 	}
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate 	if (modify_mask_arg & LAIOC_MODIFY_LACP_TIMER) {
687c478bd9Sstevel@tonic-gate 		modify_mask |= AGGR_MODIFY_LACP_TIMER;
69eae72b5bSSebastien Roy 		lacp_timer = modify_arg->lu_lacp_timer;
707c478bd9Sstevel@tonic-gate 	}
717c478bd9Sstevel@tonic-gate 
72*da14cebeSEric Cheng 	return (aggr_grp_modify(modify_arg->lu_linkid, modify_mask, policy,
73*da14cebeSEric Cheng 	    mac_fixed, mac_addr, lacp_mode, lacp_timer));
747c478bd9Sstevel@tonic-gate }
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate /*
777c478bd9Sstevel@tonic-gate  * Process a LAIOC_CREATE request.
787c478bd9Sstevel@tonic-gate  */
79eae72b5bSSebastien Roy /* ARGSUSED */
807c478bd9Sstevel@tonic-gate static int
81*da14cebeSEric Cheng aggr_ioc_create(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
827c478bd9Sstevel@tonic-gate {
83eae72b5bSSebastien Roy 	laioc_create_t *create_arg = karg;
847c478bd9Sstevel@tonic-gate 	uint16_t nports;
857c478bd9Sstevel@tonic-gate 	laioc_port_t *ports = NULL;
86eae72b5bSSebastien Roy 	size_t ports_size;
877c478bd9Sstevel@tonic-gate 	uint32_t policy;
887c478bd9Sstevel@tonic-gate 	boolean_t mac_fixed;
89d62bc4baSyz 	boolean_t force;
907c478bd9Sstevel@tonic-gate 	uchar_t mac_addr[ETHERADDRL];
917c478bd9Sstevel@tonic-gate 	aggr_lacp_mode_t lacp_mode;
927c478bd9Sstevel@tonic-gate 	aggr_lacp_timer_t lacp_timer;
93eae72b5bSSebastien Roy 	int rc;
947c478bd9Sstevel@tonic-gate 
95eae72b5bSSebastien Roy 	nports = create_arg->lc_nports;
967c478bd9Sstevel@tonic-gate 	if (nports > AGGR_MAX_PORTS)
977c478bd9Sstevel@tonic-gate 		return (EINVAL);
987c478bd9Sstevel@tonic-gate 
99eae72b5bSSebastien Roy 	policy = create_arg->lc_policy;
100eae72b5bSSebastien Roy 	lacp_mode = create_arg->lc_lacp_mode;
101eae72b5bSSebastien Roy 	lacp_timer = create_arg->lc_lacp_timer;
1027c478bd9Sstevel@tonic-gate 
103eae72b5bSSebastien Roy 	ports_size = nports * sizeof (laioc_port_t);
104eae72b5bSSebastien Roy 	ports = kmem_alloc(ports_size, KM_SLEEP);
1057c478bd9Sstevel@tonic-gate 
106eae72b5bSSebastien Roy 	if (ddi_copyin((uchar_t *)arg + sizeof (*create_arg), ports,
107eae72b5bSSebastien Roy 	    ports_size, mode) != 0) {
108eae72b5bSSebastien Roy 		rc = EFAULT;
109eae72b5bSSebastien Roy 		goto done;
110eae72b5bSSebastien Roy 	}
1117c478bd9Sstevel@tonic-gate 
112eae72b5bSSebastien Roy 	bcopy(create_arg->lc_mac, mac_addr, ETHERADDRL);
113eae72b5bSSebastien Roy 	mac_fixed = create_arg->lc_mac_fixed;
114eae72b5bSSebastien Roy 	force = create_arg->lc_force;
1157c478bd9Sstevel@tonic-gate 
116eae72b5bSSebastien Roy 	rc = aggr_grp_create(create_arg->lc_linkid, create_arg->lc_key, nports,
117eae72b5bSSebastien Roy 	    ports, policy, mac_fixed, force, mac_addr, lacp_mode, lacp_timer);
1187c478bd9Sstevel@tonic-gate 
119eae72b5bSSebastien Roy done:
120eae72b5bSSebastien Roy 	kmem_free(ports, ports_size);
1217c478bd9Sstevel@tonic-gate 	return (rc);
1227c478bd9Sstevel@tonic-gate }
1237c478bd9Sstevel@tonic-gate 
124eae72b5bSSebastien Roy /* ARGSUSED */
1257c478bd9Sstevel@tonic-gate static int
126*da14cebeSEric Cheng aggr_ioc_delete(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
1277c478bd9Sstevel@tonic-gate {
128eae72b5bSSebastien Roy 	laioc_delete_t *delete_arg = karg;
1297c478bd9Sstevel@tonic-gate 
130eae72b5bSSebastien Roy 	return (aggr_grp_delete(delete_arg->ld_linkid));
1317c478bd9Sstevel@tonic-gate }
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate typedef struct aggr_ioc_info_state {
134eae72b5bSSebastien Roy 	uint32_t	bytes_left;
135eae72b5bSSebastien Roy 	uchar_t		*where;		/* in user buffer */
136eae72b5bSSebastien Roy 	int		mode;
1377c478bd9Sstevel@tonic-gate } aggr_ioc_info_state_t;
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate static int
140d62bc4baSyz aggr_ioc_info_new_grp(void *arg, datalink_id_t linkid, uint32_t key,
141d62bc4baSyz     uchar_t *mac, boolean_t mac_fixed, boolean_t force, uint32_t policy,
142d62bc4baSyz     uint32_t nports, aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer)
1437c478bd9Sstevel@tonic-gate {
1447c478bd9Sstevel@tonic-gate 	aggr_ioc_info_state_t *state = arg;
1457c478bd9Sstevel@tonic-gate 	laioc_info_group_t grp;
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 	if (state->bytes_left < sizeof (grp))
1487c478bd9Sstevel@tonic-gate 		return (ENOSPC);
1497c478bd9Sstevel@tonic-gate 
150d62bc4baSyz 	grp.lg_linkid = linkid;
1517c478bd9Sstevel@tonic-gate 	grp.lg_key = key;
1527c478bd9Sstevel@tonic-gate 	bcopy(mac, grp.lg_mac, ETHERADDRL);
1537c478bd9Sstevel@tonic-gate 	grp.lg_mac_fixed = mac_fixed;
154d62bc4baSyz 	grp.lg_force = force;
1557c478bd9Sstevel@tonic-gate 	grp.lg_policy = policy;
1567c478bd9Sstevel@tonic-gate 	grp.lg_nports = nports;
1577c478bd9Sstevel@tonic-gate 	grp.lg_lacp_mode = lacp_mode;
1587c478bd9Sstevel@tonic-gate 	grp.lg_lacp_timer = lacp_timer;
1597c478bd9Sstevel@tonic-gate 
160eae72b5bSSebastien Roy 	if (ddi_copyout(&grp, state->where, sizeof (grp), state->mode) != 0)
161eae72b5bSSebastien Roy 		return (EFAULT);
162eae72b5bSSebastien Roy 
1637c478bd9Sstevel@tonic-gate 	state->where += sizeof (grp);
1647c478bd9Sstevel@tonic-gate 	state->bytes_left -= sizeof (grp);
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	return (0);
1677c478bd9Sstevel@tonic-gate }
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate static int
170d62bc4baSyz aggr_ioc_info_new_port(void *arg, datalink_id_t linkid, uchar_t *mac,
171ba2e4443Sseb     aggr_port_state_t portstate, aggr_lacp_state_t *lacp_state)
1727c478bd9Sstevel@tonic-gate {
1737c478bd9Sstevel@tonic-gate 	aggr_ioc_info_state_t *state = arg;
1747c478bd9Sstevel@tonic-gate 	laioc_info_port_t port;
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	if (state->bytes_left < sizeof (port))
1777c478bd9Sstevel@tonic-gate 		return (ENOSPC);
1787c478bd9Sstevel@tonic-gate 
179d62bc4baSyz 	port.lp_linkid = linkid;
1807c478bd9Sstevel@tonic-gate 	bcopy(mac, port.lp_mac, ETHERADDRL);
1817c478bd9Sstevel@tonic-gate 	port.lp_state = portstate;
1827c478bd9Sstevel@tonic-gate 	port.lp_lacp_state = *lacp_state;
1837c478bd9Sstevel@tonic-gate 
184eae72b5bSSebastien Roy 	if (ddi_copyout(&port, state->where, sizeof (port), state->mode) != 0)
185eae72b5bSSebastien Roy 		return (EFAULT);
186eae72b5bSSebastien Roy 
1877c478bd9Sstevel@tonic-gate 	state->where += sizeof (port);
1887c478bd9Sstevel@tonic-gate 	state->bytes_left -= sizeof (port);
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	return (0);
1917c478bd9Sstevel@tonic-gate }
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1947c478bd9Sstevel@tonic-gate static int
195*da14cebeSEric Cheng aggr_ioc_info(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
1967c478bd9Sstevel@tonic-gate {
197eae72b5bSSebastien Roy 	laioc_info_t *info_argp = karg;
198d62bc4baSyz 	datalink_id_t linkid;
1997c478bd9Sstevel@tonic-gate 	aggr_ioc_info_state_t state;
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	/*
202d62bc4baSyz 	 * linkid of the group to return. Must not be DATALINK_INVALID_LINKID.
2037c478bd9Sstevel@tonic-gate 	 */
204d62bc4baSyz 	if ((linkid = info_argp->li_group_linkid) == DATALINK_INVALID_LINKID)
205d62bc4baSyz 		return (EINVAL);
2067c478bd9Sstevel@tonic-gate 
207eae72b5bSSebastien Roy 	state.bytes_left = info_argp->li_bufsize - sizeof (laioc_info_t);
208eae72b5bSSebastien Roy 	state.where = (uchar_t *)arg + sizeof (laioc_info_t);
209eae72b5bSSebastien Roy 	state.mode = mode;
2107c478bd9Sstevel@tonic-gate 
211eae72b5bSSebastien Roy 	return (aggr_grp_info(linkid, &state, aggr_ioc_info_new_grp,
212eae72b5bSSebastien Roy 	    aggr_ioc_info_new_port));
2137c478bd9Sstevel@tonic-gate }
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate static int
216eae72b5bSSebastien Roy aggr_ioc_add_remove(laioc_add_rem_t *add_rem_arg, intptr_t arg, int cmd,
217eae72b5bSSebastien Roy     int mode)
2187c478bd9Sstevel@tonic-gate {
219eae72b5bSSebastien Roy 	uint16_t nports;
2207c478bd9Sstevel@tonic-gate 	laioc_port_t *ports = NULL;
221eae72b5bSSebastien Roy 	size_t ports_size;
222eae72b5bSSebastien Roy 	int rc;
2237c478bd9Sstevel@tonic-gate 
224eae72b5bSSebastien Roy 	nports = add_rem_arg->la_nports;
2257c478bd9Sstevel@tonic-gate 	if (nports > AGGR_MAX_PORTS)
2267c478bd9Sstevel@tonic-gate 		return (EINVAL);
2277c478bd9Sstevel@tonic-gate 
228eae72b5bSSebastien Roy 	ports_size = nports * sizeof (laioc_port_t);
229eae72b5bSSebastien Roy 	ports = kmem_alloc(ports_size, KM_SLEEP);
230eae72b5bSSebastien Roy 	if (ddi_copyin((uchar_t *)arg + sizeof (*add_rem_arg), ports,
231eae72b5bSSebastien Roy 	    ports_size, mode) != 0) {
232eae72b5bSSebastien Roy 		rc = EFAULT;
233eae72b5bSSebastien Roy 		goto done;
234eae72b5bSSebastien Roy 	}
2357c478bd9Sstevel@tonic-gate 
236eae72b5bSSebastien Roy 	switch (cmd) {
237eae72b5bSSebastien Roy 	case LAIOC_ADD:
238eae72b5bSSebastien Roy 		rc = aggr_grp_add_ports(add_rem_arg->la_linkid, nports,
239eae72b5bSSebastien Roy 		    add_rem_arg->la_force, ports);
240eae72b5bSSebastien Roy 		break;
241eae72b5bSSebastien Roy 	case LAIOC_REMOVE:
242eae72b5bSSebastien Roy 		rc = aggr_grp_rem_ports(add_rem_arg->la_linkid, nports, ports);
243eae72b5bSSebastien Roy 		break;
244eae72b5bSSebastien Roy 	}
2457c478bd9Sstevel@tonic-gate 
246eae72b5bSSebastien Roy done:
247eae72b5bSSebastien Roy 	kmem_free(ports, ports_size);
2487c478bd9Sstevel@tonic-gate 	return (rc);
2497c478bd9Sstevel@tonic-gate }
2507c478bd9Sstevel@tonic-gate 
251eae72b5bSSebastien Roy /* ARGSUSED */
2527c478bd9Sstevel@tonic-gate static int
253*da14cebeSEric Cheng aggr_ioc_add(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
2547c478bd9Sstevel@tonic-gate {
255eae72b5bSSebastien Roy 	return (aggr_ioc_add_remove(karg, arg, LAIOC_ADD, mode));
256eae72b5bSSebastien Roy }
2577c478bd9Sstevel@tonic-gate 
258eae72b5bSSebastien Roy /* ARGSUSED */
259eae72b5bSSebastien Roy static int
260*da14cebeSEric Cheng aggr_ioc_remove(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
261eae72b5bSSebastien Roy {
262eae72b5bSSebastien Roy 	return (aggr_ioc_add_remove(karg, arg, LAIOC_REMOVE, mode));
263eae72b5bSSebastien Roy }
2647c478bd9Sstevel@tonic-gate 
265eae72b5bSSebastien Roy static dld_ioc_info_t aggr_ioc_list[] = {
266*da14cebeSEric Cheng 	{LAIOC_CREATE, DLDCOPYIN, sizeof (laioc_create_t), aggr_ioc_create,
267*da14cebeSEric Cheng 	    {PRIV_SYS_DL_CONFIG}},
268*da14cebeSEric Cheng 	{LAIOC_DELETE, DLDCOPYIN, sizeof (laioc_delete_t), aggr_ioc_delete,
269*da14cebeSEric Cheng 	    {PRIV_SYS_DL_CONFIG}},
270*da14cebeSEric Cheng 	{LAIOC_INFO, DLDCOPYINOUT, sizeof (laioc_info_t), aggr_ioc_info,
271*da14cebeSEric Cheng 	    {NULL}},
272*da14cebeSEric Cheng 	{LAIOC_ADD, DLDCOPYIN, sizeof (laioc_add_rem_t), aggr_ioc_add,
273*da14cebeSEric Cheng 	    {PRIV_SYS_DL_CONFIG}},
274*da14cebeSEric Cheng 	{LAIOC_REMOVE, DLDCOPYIN, sizeof (laioc_add_rem_t), aggr_ioc_remove,
275*da14cebeSEric Cheng 	    {PRIV_SYS_DL_CONFIG}},
276*da14cebeSEric Cheng 	{LAIOC_MODIFY, DLDCOPYIN, sizeof (laioc_modify_t), aggr_ioc_modify,
277*da14cebeSEric Cheng 	    {PRIV_SYS_DL_CONFIG}}
278eae72b5bSSebastien Roy };
279eae72b5bSSebastien Roy 
280eae72b5bSSebastien Roy int
281eae72b5bSSebastien Roy aggr_ioc_init(void)
282eae72b5bSSebastien Roy {
283eae72b5bSSebastien Roy 	return (dld_ioc_register(AGGR_IOC, aggr_ioc_list,
284eae72b5bSSebastien Roy 	    DLDIOCCNT(aggr_ioc_list)));
2857c478bd9Sstevel@tonic-gate }
2867c478bd9Sstevel@tonic-gate 
287210db224Sericheng void
288eae72b5bSSebastien Roy aggr_ioc_fini(void)
2897c478bd9Sstevel@tonic-gate {
290eae72b5bSSebastien Roy 	dld_ioc_unregister(AGGR_IOC);
2917c478bd9Sstevel@tonic-gate }
292