xref: /onnv-gate/usr/src/uts/common/inet/iptun/iptun_dev.c (revision 11042:2d6e217af1b4)
110616SSebastien.Roy@Sun.COM /*
210616SSebastien.Roy@Sun.COM  * CDDL HEADER START
310616SSebastien.Roy@Sun.COM  *
410616SSebastien.Roy@Sun.COM  * The contents of this file are subject to the terms of the
510616SSebastien.Roy@Sun.COM  * Common Development and Distribution License (the "License").
610616SSebastien.Roy@Sun.COM  * You may not use this file except in compliance with the License.
710616SSebastien.Roy@Sun.COM  *
810616SSebastien.Roy@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910616SSebastien.Roy@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1010616SSebastien.Roy@Sun.COM  * See the License for the specific language governing permissions
1110616SSebastien.Roy@Sun.COM  * and limitations under the License.
1210616SSebastien.Roy@Sun.COM  *
1310616SSebastien.Roy@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1410616SSebastien.Roy@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510616SSebastien.Roy@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1610616SSebastien.Roy@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1710616SSebastien.Roy@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1810616SSebastien.Roy@Sun.COM  *
1910616SSebastien.Roy@Sun.COM  * CDDL HEADER END
2010616SSebastien.Roy@Sun.COM  */
2110616SSebastien.Roy@Sun.COM /*
2210616SSebastien.Roy@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2310616SSebastien.Roy@Sun.COM  * Use is subject to license terms.
2410616SSebastien.Roy@Sun.COM  */
2510616SSebastien.Roy@Sun.COM 
2610616SSebastien.Roy@Sun.COM /*
2710616SSebastien.Roy@Sun.COM  * IP Tunneling Driver
2810616SSebastien.Roy@Sun.COM  *
2910616SSebastien.Roy@Sun.COM  * As viewed from the top, this module is a GLDv3 driver that consumes the
3010616SSebastien.Roy@Sun.COM  * mac driver interfaces.  It implements the logic for various forms of IP
3110616SSebastien.Roy@Sun.COM  * (IPv4 or IPv6) encapsulation within IP (IPv4 or IPv6).
3210616SSebastien.Roy@Sun.COM  */
3310616SSebastien.Roy@Sun.COM 
3410616SSebastien.Roy@Sun.COM #include <sys/file.h>
3510616SSebastien.Roy@Sun.COM #include <sys/list.h>
3610616SSebastien.Roy@Sun.COM #include "iptun_impl.h"
3710616SSebastien.Roy@Sun.COM 
3810616SSebastien.Roy@Sun.COM #define	IPTUN_LINKINFO		"IP tunneling driver"
3910616SSebastien.Roy@Sun.COM #define	IPTUN_HASHSZ		67
4010616SSebastien.Roy@Sun.COM 
4110616SSebastien.Roy@Sun.COM dev_info_t	*iptun_dip;
4210616SSebastien.Roy@Sun.COM ldi_ident_t	iptun_ldi_ident;
4310616SSebastien.Roy@Sun.COM 
4410616SSebastien.Roy@Sun.COM static int	iptun_attach(dev_info_t *, ddi_attach_cmd_t);
4510616SSebastien.Roy@Sun.COM static int	iptun_detach(dev_info_t *, ddi_detach_cmd_t);
4610616SSebastien.Roy@Sun.COM static int	iptun_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
4710616SSebastien.Roy@Sun.COM static int	iptun_constructor(void *, void *, int);
4810616SSebastien.Roy@Sun.COM static void	iptun_destructor(void *, void *);
4910616SSebastien.Roy@Sun.COM 
5010616SSebastien.Roy@Sun.COM DDI_DEFINE_STREAM_OPS(iptun_dev_ops, nulldev, nulldev, iptun_attach,
5110616SSebastien.Roy@Sun.COM     iptun_detach, nodev, iptun_getinfo, D_MP, NULL, ddi_quiesce_not_supported);
5210616SSebastien.Roy@Sun.COM 
5310616SSebastien.Roy@Sun.COM static struct modldrv iptun_modldrv = {
5410616SSebastien.Roy@Sun.COM 	&mod_driverops,
5510616SSebastien.Roy@Sun.COM 	IPTUN_LINKINFO,
5610616SSebastien.Roy@Sun.COM 	&iptun_dev_ops
5710616SSebastien.Roy@Sun.COM };
5810616SSebastien.Roy@Sun.COM 
5910616SSebastien.Roy@Sun.COM static struct modlinkage iptun_modlinkage = {
6010616SSebastien.Roy@Sun.COM 	MODREV_1,
6110616SSebastien.Roy@Sun.COM 	&iptun_modldrv,
6210616SSebastien.Roy@Sun.COM 	NULL
6310616SSebastien.Roy@Sun.COM };
6410616SSebastien.Roy@Sun.COM 
6510616SSebastien.Roy@Sun.COM /*
6610616SSebastien.Roy@Sun.COM  * Initialize the tunnel stack instance.
6710616SSebastien.Roy@Sun.COM  */
6810616SSebastien.Roy@Sun.COM /* ARGSUSED */
6910616SSebastien.Roy@Sun.COM static void *
iptun_stack_init(netstackid_t stackid,netstack_t * ns)7010616SSebastien.Roy@Sun.COM iptun_stack_init(netstackid_t stackid, netstack_t *ns)
7110616SSebastien.Roy@Sun.COM {
7210616SSebastien.Roy@Sun.COM 	iptun_stack_t	*iptuns;
7310616SSebastien.Roy@Sun.COM 
7410616SSebastien.Roy@Sun.COM 	iptuns = kmem_zalloc(sizeof (*iptuns), KM_SLEEP);
7510616SSebastien.Roy@Sun.COM 	iptuns->iptuns_netstack = ns;
7610616SSebastien.Roy@Sun.COM 	mutex_init(&iptuns->iptuns_lock, NULL, MUTEX_DEFAULT, NULL);
7710616SSebastien.Roy@Sun.COM 	list_create(&iptuns->iptuns_iptunlist, sizeof (iptun_t),
7810616SSebastien.Roy@Sun.COM 	    offsetof(iptun_t, iptun_link));
7910616SSebastien.Roy@Sun.COM 
8010616SSebastien.Roy@Sun.COM 	return (iptuns);
8110616SSebastien.Roy@Sun.COM }
8210616SSebastien.Roy@Sun.COM 
8310616SSebastien.Roy@Sun.COM /* ARGSUSED */
8410616SSebastien.Roy@Sun.COM static void
iptun_stack_shutdown(netstackid_t stackid,void * arg)8510616SSebastien.Roy@Sun.COM iptun_stack_shutdown(netstackid_t stackid, void *arg)
8610616SSebastien.Roy@Sun.COM {
8710616SSebastien.Roy@Sun.COM 	iptun_stack_t	*iptuns = arg;
8810616SSebastien.Roy@Sun.COM 	iptun_t		*iptun;
8910616SSebastien.Roy@Sun.COM 	datalink_id_t	linkid;
9010616SSebastien.Roy@Sun.COM 
9110616SSebastien.Roy@Sun.COM 	/* note that iptun_delete() removes iptun from the list */
9210616SSebastien.Roy@Sun.COM 	while ((iptun = list_head(&iptuns->iptuns_iptunlist)) != NULL) {
9310616SSebastien.Roy@Sun.COM 		linkid = iptun->iptun_linkid;
94*11042SErik.Nordmark@Sun.COM 		(void) iptun_delete(linkid, iptun->iptun_connp->conn_cred);
9510616SSebastien.Roy@Sun.COM 		(void) dls_mgmt_destroy(linkid, B_FALSE);
9610616SSebastien.Roy@Sun.COM 	}
9710616SSebastien.Roy@Sun.COM }
9810616SSebastien.Roy@Sun.COM 
9910616SSebastien.Roy@Sun.COM /*
10010616SSebastien.Roy@Sun.COM  * Free the tunnel stack instance.
10110616SSebastien.Roy@Sun.COM  */
10210616SSebastien.Roy@Sun.COM /* ARGSUSED */
10310616SSebastien.Roy@Sun.COM static void
iptun_stack_fini(netstackid_t stackid,void * arg)10410616SSebastien.Roy@Sun.COM iptun_stack_fini(netstackid_t stackid, void *arg)
10510616SSebastien.Roy@Sun.COM {
10610616SSebastien.Roy@Sun.COM 	iptun_stack_t *iptuns = arg;
10710616SSebastien.Roy@Sun.COM 
10810616SSebastien.Roy@Sun.COM 	list_destroy(&iptuns->iptuns_iptunlist);
10910616SSebastien.Roy@Sun.COM 	mutex_destroy(&iptuns->iptuns_lock);
11010616SSebastien.Roy@Sun.COM 	kmem_free(iptuns, sizeof (*iptuns));
11110616SSebastien.Roy@Sun.COM }
11210616SSebastien.Roy@Sun.COM 
11310616SSebastien.Roy@Sun.COM static void
iptun_fini(void)11410616SSebastien.Roy@Sun.COM iptun_fini(void)
11510616SSebastien.Roy@Sun.COM {
11610616SSebastien.Roy@Sun.COM 	ddi_taskq_destroy(iptun_taskq);
11710616SSebastien.Roy@Sun.COM 	mac_fini_ops(&iptun_dev_ops);
11810616SSebastien.Roy@Sun.COM 	ldi_ident_release(iptun_ldi_ident);
11910616SSebastien.Roy@Sun.COM 	mod_hash_destroy_idhash(iptun_hash);
12010616SSebastien.Roy@Sun.COM 	kmem_cache_destroy(iptun_cache);
12110616SSebastien.Roy@Sun.COM }
12210616SSebastien.Roy@Sun.COM 
12310616SSebastien.Roy@Sun.COM int
_init(void)12410616SSebastien.Roy@Sun.COM _init(void)
12510616SSebastien.Roy@Sun.COM {
12610616SSebastien.Roy@Sun.COM 	int rc;
12710616SSebastien.Roy@Sun.COM 
12810616SSebastien.Roy@Sun.COM 	rc = ldi_ident_from_mod(&iptun_modlinkage, &iptun_ldi_ident);
12910616SSebastien.Roy@Sun.COM 	if (rc != 0)
13010616SSebastien.Roy@Sun.COM 		return (rc);
13110616SSebastien.Roy@Sun.COM 
13210616SSebastien.Roy@Sun.COM 	iptun_cache = kmem_cache_create("iptun_cache", sizeof (iptun_t), 0,
13310616SSebastien.Roy@Sun.COM 	    iptun_constructor, iptun_destructor, NULL, NULL, NULL, 0);
13410616SSebastien.Roy@Sun.COM 	if (iptun_cache == NULL) {
13510616SSebastien.Roy@Sun.COM 		ldi_ident_release(iptun_ldi_ident);
13610616SSebastien.Roy@Sun.COM 		return (ENOMEM);
13710616SSebastien.Roy@Sun.COM 	}
13810616SSebastien.Roy@Sun.COM 
13910616SSebastien.Roy@Sun.COM 	iptun_taskq = ddi_taskq_create(NULL, "iptun_taskq", 1,
14010616SSebastien.Roy@Sun.COM 	    TASKQ_DEFAULTPRI, 0);
14110616SSebastien.Roy@Sun.COM 	if (iptun_taskq == NULL) {
14210616SSebastien.Roy@Sun.COM 		ldi_ident_release(iptun_ldi_ident);
14310616SSebastien.Roy@Sun.COM 		kmem_cache_destroy(iptun_cache);
14410616SSebastien.Roy@Sun.COM 		return (ENOMEM);
14510616SSebastien.Roy@Sun.COM 	}
14610616SSebastien.Roy@Sun.COM 
14710616SSebastien.Roy@Sun.COM 	iptun_hash = mod_hash_create_idhash("iptun_hash", IPTUN_HASHSZ,
14810616SSebastien.Roy@Sun.COM 	    mod_hash_null_valdtor);
14910616SSebastien.Roy@Sun.COM 
15010616SSebastien.Roy@Sun.COM 	mac_init_ops(&iptun_dev_ops, IPTUN_DRIVER_NAME);
15110616SSebastien.Roy@Sun.COM 
15210616SSebastien.Roy@Sun.COM 	if ((rc = mod_install(&iptun_modlinkage)) != 0)
15310616SSebastien.Roy@Sun.COM 		iptun_fini();
15410616SSebastien.Roy@Sun.COM 	return (rc);
15510616SSebastien.Roy@Sun.COM }
15610616SSebastien.Roy@Sun.COM 
15710616SSebastien.Roy@Sun.COM int
_fini(void)15810616SSebastien.Roy@Sun.COM _fini(void)
15910616SSebastien.Roy@Sun.COM {
16010616SSebastien.Roy@Sun.COM 	int rc;
16110616SSebastien.Roy@Sun.COM 
16210616SSebastien.Roy@Sun.COM 	if ((rc = mod_remove(&iptun_modlinkage)) == 0)
16310616SSebastien.Roy@Sun.COM 		iptun_fini();
16410616SSebastien.Roy@Sun.COM 	return (rc);
16510616SSebastien.Roy@Sun.COM }
16610616SSebastien.Roy@Sun.COM 
16710616SSebastien.Roy@Sun.COM int
_info(struct modinfo * modinfop)16810616SSebastien.Roy@Sun.COM _info(struct modinfo *modinfop)
16910616SSebastien.Roy@Sun.COM {
17010616SSebastien.Roy@Sun.COM 	return (mod_info(&iptun_modlinkage, modinfop));
17110616SSebastien.Roy@Sun.COM }
17210616SSebastien.Roy@Sun.COM 
17310616SSebastien.Roy@Sun.COM static int
iptun_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)17410616SSebastien.Roy@Sun.COM iptun_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
17510616SSebastien.Roy@Sun.COM {
17610616SSebastien.Roy@Sun.COM 	switch (cmd) {
17710616SSebastien.Roy@Sun.COM 	case DDI_ATTACH:
17810616SSebastien.Roy@Sun.COM 		if (ddi_get_instance(dip) != 0 || iptun_ioc_init() != 0)
17910616SSebastien.Roy@Sun.COM 			return (DDI_FAILURE);
18010616SSebastien.Roy@Sun.COM 		iptun_dip = dip;
18110616SSebastien.Roy@Sun.COM 		netstack_register(NS_IPTUN, iptun_stack_init,
18210616SSebastien.Roy@Sun.COM 		    iptun_stack_shutdown, iptun_stack_fini);
18310616SSebastien.Roy@Sun.COM 		return (DDI_SUCCESS);
18410616SSebastien.Roy@Sun.COM 
18510616SSebastien.Roy@Sun.COM 	default:
18610616SSebastien.Roy@Sun.COM 		return (DDI_FAILURE);
18710616SSebastien.Roy@Sun.COM 	}
18810616SSebastien.Roy@Sun.COM }
18910616SSebastien.Roy@Sun.COM 
19010616SSebastien.Roy@Sun.COM /* ARGSUSED */
19110616SSebastien.Roy@Sun.COM static int
iptun_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)19210616SSebastien.Roy@Sun.COM iptun_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
19310616SSebastien.Roy@Sun.COM {
19410616SSebastien.Roy@Sun.COM 	switch (cmd) {
19510616SSebastien.Roy@Sun.COM 	case DDI_DETACH:
19610616SSebastien.Roy@Sun.COM 		/*
19710616SSebastien.Roy@Sun.COM 		 * We prevent the pseudo device from detaching (and thus the
19810616SSebastien.Roy@Sun.COM 		 * driver from unloading) when there are tunnels configured by
19910616SSebastien.Roy@Sun.COM 		 * consulting iptun_count().  We don't need to hold a lock
20010616SSebastien.Roy@Sun.COM 		 * here because the tunnel count is only changed when a tunnel
20110616SSebastien.Roy@Sun.COM 		 * is created or deleted, which can't happen while the detach
20210616SSebastien.Roy@Sun.COM 		 * routine is running (the ioctl path calls
20310616SSebastien.Roy@Sun.COM 		 * ddi_hold_devi_by_instance() in dld's drv_ioctl(), and the
20410616SSebastien.Roy@Sun.COM 		 * /dev/net implicit path has the device open).
20510616SSebastien.Roy@Sun.COM 		 */
20610616SSebastien.Roy@Sun.COM 		if (iptun_count() > 0)
20710616SSebastien.Roy@Sun.COM 			return (DDI_FAILURE);
20810616SSebastien.Roy@Sun.COM 		netstack_unregister(NS_IPTUN);
20910616SSebastien.Roy@Sun.COM 		iptun_dip = NULL;
21010616SSebastien.Roy@Sun.COM 		iptun_ioc_fini();
21110616SSebastien.Roy@Sun.COM 		return (DDI_SUCCESS);
21210616SSebastien.Roy@Sun.COM 
21310616SSebastien.Roy@Sun.COM 	default:
21410616SSebastien.Roy@Sun.COM 		return (DDI_FAILURE);
21510616SSebastien.Roy@Sun.COM 	}
21610616SSebastien.Roy@Sun.COM }
21710616SSebastien.Roy@Sun.COM 
21810616SSebastien.Roy@Sun.COM /* ARGSUSED */
21910616SSebastien.Roy@Sun.COM static int
iptun_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)22010616SSebastien.Roy@Sun.COM iptun_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
22110616SSebastien.Roy@Sun.COM {
22210616SSebastien.Roy@Sun.COM 	switch (infocmd) {
22310616SSebastien.Roy@Sun.COM 	case DDI_INFO_DEVT2DEVINFO:
22410616SSebastien.Roy@Sun.COM 		*result = iptun_dip;
22510616SSebastien.Roy@Sun.COM 		return (DDI_SUCCESS);
22610616SSebastien.Roy@Sun.COM 	case DDI_INFO_DEVT2INSTANCE:
22710616SSebastien.Roy@Sun.COM 		*result = NULL;
22810616SSebastien.Roy@Sun.COM 		return (DDI_SUCCESS);
22910616SSebastien.Roy@Sun.COM 	}
23010616SSebastien.Roy@Sun.COM 	return (DDI_FAILURE);
23110616SSebastien.Roy@Sun.COM }
23210616SSebastien.Roy@Sun.COM 
23310616SSebastien.Roy@Sun.COM /* ARGSUSED */
23410616SSebastien.Roy@Sun.COM static int
iptun_constructor(void * buf,void * cdrarg,int kmflags)23510616SSebastien.Roy@Sun.COM iptun_constructor(void *buf, void *cdrarg, int kmflags)
23610616SSebastien.Roy@Sun.COM {
23710616SSebastien.Roy@Sun.COM 	iptun_t	*iptun = buf;
23810616SSebastien.Roy@Sun.COM 
23910616SSebastien.Roy@Sun.COM 	bzero(iptun, sizeof (*iptun));
24010616SSebastien.Roy@Sun.COM 	mutex_init(&iptun->iptun_lock, NULL, MUTEX_DEFAULT, NULL);
24110616SSebastien.Roy@Sun.COM 	cv_init(&iptun->iptun_upcall_cv, NULL, CV_DRIVER, NULL);
24210616SSebastien.Roy@Sun.COM 	cv_init(&iptun->iptun_enter_cv, NULL, CV_DRIVER, NULL);
24310616SSebastien.Roy@Sun.COM 
24410616SSebastien.Roy@Sun.COM 	return (0);
24510616SSebastien.Roy@Sun.COM }
24610616SSebastien.Roy@Sun.COM 
24710616SSebastien.Roy@Sun.COM /* ARGSUSED */
24810616SSebastien.Roy@Sun.COM static void
iptun_destructor(void * buf,void * cdrarg)24910616SSebastien.Roy@Sun.COM iptun_destructor(void *buf, void *cdrarg)
25010616SSebastien.Roy@Sun.COM {
25110616SSebastien.Roy@Sun.COM 	iptun_t *iptun = buf;
25210616SSebastien.Roy@Sun.COM 
25310616SSebastien.Roy@Sun.COM 	/* This iptun_t must not still be in use. */
25410616SSebastien.Roy@Sun.COM 	ASSERT(!(iptun->iptun_flags & (IPTUN_BOUND|IPTUN_MAC_REGISTERED|
25510616SSebastien.Roy@Sun.COM 	    IPTUN_MAC_STARTED|IPTUN_HASH_INSERTED|IPTUN_UPCALL_PENDING)));
25610616SSebastien.Roy@Sun.COM 
25710616SSebastien.Roy@Sun.COM 	mutex_destroy(&iptun->iptun_lock);
25810616SSebastien.Roy@Sun.COM 	cv_destroy(&iptun->iptun_upcall_cv);
25910616SSebastien.Roy@Sun.COM }
260