xref: /illumos-gate/usr/src/uts/common/inet/iptun/iptun_dev.c (revision bd670b35a010421b6e1a5536c34453a827007c81)
12b24ab6bSSebastien Roy /*
22b24ab6bSSebastien Roy  * CDDL HEADER START
32b24ab6bSSebastien Roy  *
42b24ab6bSSebastien Roy  * The contents of this file are subject to the terms of the
52b24ab6bSSebastien Roy  * Common Development and Distribution License (the "License").
62b24ab6bSSebastien Roy  * You may not use this file except in compliance with the License.
72b24ab6bSSebastien Roy  *
82b24ab6bSSebastien Roy  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92b24ab6bSSebastien Roy  * or http://www.opensolaris.org/os/licensing.
102b24ab6bSSebastien Roy  * See the License for the specific language governing permissions
112b24ab6bSSebastien Roy  * and limitations under the License.
122b24ab6bSSebastien Roy  *
132b24ab6bSSebastien Roy  * When distributing Covered Code, include this CDDL HEADER in each
142b24ab6bSSebastien Roy  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152b24ab6bSSebastien Roy  * If applicable, add the following below this CDDL HEADER, with the
162b24ab6bSSebastien Roy  * fields enclosed by brackets "[]" replaced with your own identifying
172b24ab6bSSebastien Roy  * information: Portions Copyright [yyyy] [name of copyright owner]
182b24ab6bSSebastien Roy  *
192b24ab6bSSebastien Roy  * CDDL HEADER END
202b24ab6bSSebastien Roy  */
212b24ab6bSSebastien Roy /*
222b24ab6bSSebastien Roy  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
232b24ab6bSSebastien Roy  * Use is subject to license terms.
242b24ab6bSSebastien Roy  */
252b24ab6bSSebastien Roy 
262b24ab6bSSebastien Roy /*
272b24ab6bSSebastien Roy  * IP Tunneling Driver
282b24ab6bSSebastien Roy  *
292b24ab6bSSebastien Roy  * As viewed from the top, this module is a GLDv3 driver that consumes the
302b24ab6bSSebastien Roy  * mac driver interfaces.  It implements the logic for various forms of IP
312b24ab6bSSebastien Roy  * (IPv4 or IPv6) encapsulation within IP (IPv4 or IPv6).
322b24ab6bSSebastien Roy  */
332b24ab6bSSebastien Roy 
342b24ab6bSSebastien Roy #include <sys/file.h>
352b24ab6bSSebastien Roy #include <sys/list.h>
362b24ab6bSSebastien Roy #include "iptun_impl.h"
372b24ab6bSSebastien Roy 
382b24ab6bSSebastien Roy #define	IPTUN_LINKINFO		"IP tunneling driver"
392b24ab6bSSebastien Roy #define	IPTUN_HASHSZ		67
402b24ab6bSSebastien Roy 
412b24ab6bSSebastien Roy dev_info_t	*iptun_dip;
422b24ab6bSSebastien Roy ldi_ident_t	iptun_ldi_ident;
432b24ab6bSSebastien Roy 
442b24ab6bSSebastien Roy static int	iptun_attach(dev_info_t *, ddi_attach_cmd_t);
452b24ab6bSSebastien Roy static int	iptun_detach(dev_info_t *, ddi_detach_cmd_t);
462b24ab6bSSebastien Roy static int	iptun_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
472b24ab6bSSebastien Roy static int	iptun_constructor(void *, void *, int);
482b24ab6bSSebastien Roy static void	iptun_destructor(void *, void *);
492b24ab6bSSebastien Roy 
502b24ab6bSSebastien Roy DDI_DEFINE_STREAM_OPS(iptun_dev_ops, nulldev, nulldev, iptun_attach,
512b24ab6bSSebastien Roy     iptun_detach, nodev, iptun_getinfo, D_MP, NULL, ddi_quiesce_not_supported);
522b24ab6bSSebastien Roy 
532b24ab6bSSebastien Roy static struct modldrv iptun_modldrv = {
542b24ab6bSSebastien Roy 	&mod_driverops,
552b24ab6bSSebastien Roy 	IPTUN_LINKINFO,
562b24ab6bSSebastien Roy 	&iptun_dev_ops
572b24ab6bSSebastien Roy };
582b24ab6bSSebastien Roy 
592b24ab6bSSebastien Roy static struct modlinkage iptun_modlinkage = {
602b24ab6bSSebastien Roy 	MODREV_1,
612b24ab6bSSebastien Roy 	&iptun_modldrv,
622b24ab6bSSebastien Roy 	NULL
632b24ab6bSSebastien Roy };
642b24ab6bSSebastien Roy 
652b24ab6bSSebastien Roy /*
662b24ab6bSSebastien Roy  * Initialize the tunnel stack instance.
672b24ab6bSSebastien Roy  */
682b24ab6bSSebastien Roy /* ARGSUSED */
692b24ab6bSSebastien Roy static void *
iptun_stack_init(netstackid_t stackid,netstack_t * ns)702b24ab6bSSebastien Roy iptun_stack_init(netstackid_t stackid, netstack_t *ns)
712b24ab6bSSebastien Roy {
722b24ab6bSSebastien Roy 	iptun_stack_t	*iptuns;
732b24ab6bSSebastien Roy 
742b24ab6bSSebastien Roy 	iptuns = kmem_zalloc(sizeof (*iptuns), KM_SLEEP);
752b24ab6bSSebastien Roy 	iptuns->iptuns_netstack = ns;
762b24ab6bSSebastien Roy 	mutex_init(&iptuns->iptuns_lock, NULL, MUTEX_DEFAULT, NULL);
772b24ab6bSSebastien Roy 	list_create(&iptuns->iptuns_iptunlist, sizeof (iptun_t),
782b24ab6bSSebastien Roy 	    offsetof(iptun_t, iptun_link));
792b24ab6bSSebastien Roy 
802b24ab6bSSebastien Roy 	return (iptuns);
812b24ab6bSSebastien Roy }
822b24ab6bSSebastien Roy 
832b24ab6bSSebastien Roy /* ARGSUSED */
842b24ab6bSSebastien Roy static void
iptun_stack_shutdown(netstackid_t stackid,void * arg)852b24ab6bSSebastien Roy iptun_stack_shutdown(netstackid_t stackid, void *arg)
862b24ab6bSSebastien Roy {
872b24ab6bSSebastien Roy 	iptun_stack_t	*iptuns = arg;
882b24ab6bSSebastien Roy 	iptun_t		*iptun;
892b24ab6bSSebastien Roy 	datalink_id_t	linkid;
902b24ab6bSSebastien Roy 
912b24ab6bSSebastien Roy 	/* note that iptun_delete() removes iptun from the list */
922b24ab6bSSebastien Roy 	while ((iptun = list_head(&iptuns->iptuns_iptunlist)) != NULL) {
932b24ab6bSSebastien Roy 		linkid = iptun->iptun_linkid;
94*bd670b35SErik Nordmark 		(void) iptun_delete(linkid, iptun->iptun_connp->conn_cred);
952b24ab6bSSebastien Roy 		(void) dls_mgmt_destroy(linkid, B_FALSE);
962b24ab6bSSebastien Roy 	}
972b24ab6bSSebastien Roy }
982b24ab6bSSebastien Roy 
992b24ab6bSSebastien Roy /*
1002b24ab6bSSebastien Roy  * Free the tunnel stack instance.
1012b24ab6bSSebastien Roy  */
1022b24ab6bSSebastien Roy /* ARGSUSED */
1032b24ab6bSSebastien Roy static void
iptun_stack_fini(netstackid_t stackid,void * arg)1042b24ab6bSSebastien Roy iptun_stack_fini(netstackid_t stackid, void *arg)
1052b24ab6bSSebastien Roy {
1062b24ab6bSSebastien Roy 	iptun_stack_t *iptuns = arg;
1072b24ab6bSSebastien Roy 
1082b24ab6bSSebastien Roy 	list_destroy(&iptuns->iptuns_iptunlist);
1092b24ab6bSSebastien Roy 	mutex_destroy(&iptuns->iptuns_lock);
1102b24ab6bSSebastien Roy 	kmem_free(iptuns, sizeof (*iptuns));
1112b24ab6bSSebastien Roy }
1122b24ab6bSSebastien Roy 
1132b24ab6bSSebastien Roy static void
iptun_fini(void)1142b24ab6bSSebastien Roy iptun_fini(void)
1152b24ab6bSSebastien Roy {
1162b24ab6bSSebastien Roy 	ddi_taskq_destroy(iptun_taskq);
1172b24ab6bSSebastien Roy 	mac_fini_ops(&iptun_dev_ops);
1182b24ab6bSSebastien Roy 	ldi_ident_release(iptun_ldi_ident);
1192b24ab6bSSebastien Roy 	mod_hash_destroy_idhash(iptun_hash);
1202b24ab6bSSebastien Roy 	kmem_cache_destroy(iptun_cache);
1212b24ab6bSSebastien Roy }
1222b24ab6bSSebastien Roy 
1232b24ab6bSSebastien Roy int
_init(void)1242b24ab6bSSebastien Roy _init(void)
1252b24ab6bSSebastien Roy {
1262b24ab6bSSebastien Roy 	int rc;
1272b24ab6bSSebastien Roy 
1282b24ab6bSSebastien Roy 	rc = ldi_ident_from_mod(&iptun_modlinkage, &iptun_ldi_ident);
1292b24ab6bSSebastien Roy 	if (rc != 0)
1302b24ab6bSSebastien Roy 		return (rc);
1312b24ab6bSSebastien Roy 
1322b24ab6bSSebastien Roy 	iptun_cache = kmem_cache_create("iptun_cache", sizeof (iptun_t), 0,
1332b24ab6bSSebastien Roy 	    iptun_constructor, iptun_destructor, NULL, NULL, NULL, 0);
1342b24ab6bSSebastien Roy 	if (iptun_cache == NULL) {
1352b24ab6bSSebastien Roy 		ldi_ident_release(iptun_ldi_ident);
1362b24ab6bSSebastien Roy 		return (ENOMEM);
1372b24ab6bSSebastien Roy 	}
1382b24ab6bSSebastien Roy 
1392b24ab6bSSebastien Roy 	iptun_taskq = ddi_taskq_create(NULL, "iptun_taskq", 1,
1402b24ab6bSSebastien Roy 	    TASKQ_DEFAULTPRI, 0);
1412b24ab6bSSebastien Roy 	if (iptun_taskq == NULL) {
1422b24ab6bSSebastien Roy 		ldi_ident_release(iptun_ldi_ident);
1432b24ab6bSSebastien Roy 		kmem_cache_destroy(iptun_cache);
1442b24ab6bSSebastien Roy 		return (ENOMEM);
1452b24ab6bSSebastien Roy 	}
1462b24ab6bSSebastien Roy 
1472b24ab6bSSebastien Roy 	iptun_hash = mod_hash_create_idhash("iptun_hash", IPTUN_HASHSZ,
1482b24ab6bSSebastien Roy 	    mod_hash_null_valdtor);
1492b24ab6bSSebastien Roy 
1502b24ab6bSSebastien Roy 	mac_init_ops(&iptun_dev_ops, IPTUN_DRIVER_NAME);
1512b24ab6bSSebastien Roy 
1522b24ab6bSSebastien Roy 	if ((rc = mod_install(&iptun_modlinkage)) != 0)
1532b24ab6bSSebastien Roy 		iptun_fini();
1542b24ab6bSSebastien Roy 	return (rc);
1552b24ab6bSSebastien Roy }
1562b24ab6bSSebastien Roy 
1572b24ab6bSSebastien Roy int
_fini(void)1582b24ab6bSSebastien Roy _fini(void)
1592b24ab6bSSebastien Roy {
1602b24ab6bSSebastien Roy 	int rc;
1612b24ab6bSSebastien Roy 
1622b24ab6bSSebastien Roy 	if ((rc = mod_remove(&iptun_modlinkage)) == 0)
1632b24ab6bSSebastien Roy 		iptun_fini();
1642b24ab6bSSebastien Roy 	return (rc);
1652b24ab6bSSebastien Roy }
1662b24ab6bSSebastien Roy 
1672b24ab6bSSebastien Roy int
_info(struct modinfo * modinfop)1682b24ab6bSSebastien Roy _info(struct modinfo *modinfop)
1692b24ab6bSSebastien Roy {
1702b24ab6bSSebastien Roy 	return (mod_info(&iptun_modlinkage, modinfop));
1712b24ab6bSSebastien Roy }
1722b24ab6bSSebastien Roy 
1732b24ab6bSSebastien Roy static int
iptun_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)1742b24ab6bSSebastien Roy iptun_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1752b24ab6bSSebastien Roy {
1762b24ab6bSSebastien Roy 	switch (cmd) {
1772b24ab6bSSebastien Roy 	case DDI_ATTACH:
1782b24ab6bSSebastien Roy 		if (ddi_get_instance(dip) != 0 || iptun_ioc_init() != 0)
1792b24ab6bSSebastien Roy 			return (DDI_FAILURE);
1802b24ab6bSSebastien Roy 		iptun_dip = dip;
1812b24ab6bSSebastien Roy 		netstack_register(NS_IPTUN, iptun_stack_init,
1822b24ab6bSSebastien Roy 		    iptun_stack_shutdown, iptun_stack_fini);
1832b24ab6bSSebastien Roy 		return (DDI_SUCCESS);
1842b24ab6bSSebastien Roy 
1852b24ab6bSSebastien Roy 	default:
1862b24ab6bSSebastien Roy 		return (DDI_FAILURE);
1872b24ab6bSSebastien Roy 	}
1882b24ab6bSSebastien Roy }
1892b24ab6bSSebastien Roy 
1902b24ab6bSSebastien Roy /* ARGSUSED */
1912b24ab6bSSebastien Roy static int
iptun_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)1922b24ab6bSSebastien Roy iptun_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
1932b24ab6bSSebastien Roy {
1942b24ab6bSSebastien Roy 	switch (cmd) {
1952b24ab6bSSebastien Roy 	case DDI_DETACH:
1962b24ab6bSSebastien Roy 		/*
1972b24ab6bSSebastien Roy 		 * We prevent the pseudo device from detaching (and thus the
1982b24ab6bSSebastien Roy 		 * driver from unloading) when there are tunnels configured by
1992b24ab6bSSebastien Roy 		 * consulting iptun_count().  We don't need to hold a lock
2002b24ab6bSSebastien Roy 		 * here because the tunnel count is only changed when a tunnel
2012b24ab6bSSebastien Roy 		 * is created or deleted, which can't happen while the detach
2022b24ab6bSSebastien Roy 		 * routine is running (the ioctl path calls
2032b24ab6bSSebastien Roy 		 * ddi_hold_devi_by_instance() in dld's drv_ioctl(), and the
2042b24ab6bSSebastien Roy 		 * /dev/net implicit path has the device open).
2052b24ab6bSSebastien Roy 		 */
2062b24ab6bSSebastien Roy 		if (iptun_count() > 0)
2072b24ab6bSSebastien Roy 			return (DDI_FAILURE);
2082b24ab6bSSebastien Roy 		netstack_unregister(NS_IPTUN);
2092b24ab6bSSebastien Roy 		iptun_dip = NULL;
2102b24ab6bSSebastien Roy 		iptun_ioc_fini();
2112b24ab6bSSebastien Roy 		return (DDI_SUCCESS);
2122b24ab6bSSebastien Roy 
2132b24ab6bSSebastien Roy 	default:
2142b24ab6bSSebastien Roy 		return (DDI_FAILURE);
2152b24ab6bSSebastien Roy 	}
2162b24ab6bSSebastien Roy }
2172b24ab6bSSebastien Roy 
2182b24ab6bSSebastien Roy /* ARGSUSED */
2192b24ab6bSSebastien Roy static int
iptun_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)2202b24ab6bSSebastien Roy iptun_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
2212b24ab6bSSebastien Roy {
2222b24ab6bSSebastien Roy 	switch (infocmd) {
2232b24ab6bSSebastien Roy 	case DDI_INFO_DEVT2DEVINFO:
2242b24ab6bSSebastien Roy 		*result = iptun_dip;
2252b24ab6bSSebastien Roy 		return (DDI_SUCCESS);
2262b24ab6bSSebastien Roy 	case DDI_INFO_DEVT2INSTANCE:
2272b24ab6bSSebastien Roy 		*result = NULL;
2282b24ab6bSSebastien Roy 		return (DDI_SUCCESS);
2292b24ab6bSSebastien Roy 	}
2302b24ab6bSSebastien Roy 	return (DDI_FAILURE);
2312b24ab6bSSebastien Roy }
2322b24ab6bSSebastien Roy 
2332b24ab6bSSebastien Roy /* ARGSUSED */
2342b24ab6bSSebastien Roy static int
iptun_constructor(void * buf,void * cdrarg,int kmflags)2352b24ab6bSSebastien Roy iptun_constructor(void *buf, void *cdrarg, int kmflags)
2362b24ab6bSSebastien Roy {
2372b24ab6bSSebastien Roy 	iptun_t	*iptun = buf;
2382b24ab6bSSebastien Roy 
2392b24ab6bSSebastien Roy 	bzero(iptun, sizeof (*iptun));
2402b24ab6bSSebastien Roy 	mutex_init(&iptun->iptun_lock, NULL, MUTEX_DEFAULT, NULL);
2412b24ab6bSSebastien Roy 	cv_init(&iptun->iptun_upcall_cv, NULL, CV_DRIVER, NULL);
2422b24ab6bSSebastien Roy 	cv_init(&iptun->iptun_enter_cv, NULL, CV_DRIVER, NULL);
2432b24ab6bSSebastien Roy 
2442b24ab6bSSebastien Roy 	return (0);
2452b24ab6bSSebastien Roy }
2462b24ab6bSSebastien Roy 
2472b24ab6bSSebastien Roy /* ARGSUSED */
2482b24ab6bSSebastien Roy static void
iptun_destructor(void * buf,void * cdrarg)2492b24ab6bSSebastien Roy iptun_destructor(void *buf, void *cdrarg)
2502b24ab6bSSebastien Roy {
2512b24ab6bSSebastien Roy 	iptun_t *iptun = buf;
2522b24ab6bSSebastien Roy 
2532b24ab6bSSebastien Roy 	/* This iptun_t must not still be in use. */
2542b24ab6bSSebastien Roy 	ASSERT(!(iptun->iptun_flags & (IPTUN_BOUND|IPTUN_MAC_REGISTERED|
2552b24ab6bSSebastien Roy 	    IPTUN_MAC_STARTED|IPTUN_HASH_INSERTED|IPTUN_UPCALL_PENDING)));
2562b24ab6bSSebastien Roy 
2572b24ab6bSSebastien Roy 	mutex_destroy(&iptun->iptun_lock);
2582b24ab6bSSebastien Roy 	cv_destroy(&iptun->iptun_upcall_cv);
2592b24ab6bSSebastien Roy }
260