xref: /titanic_52/usr/src/lib/libdladm/common/libdliptun.c (revision 327151705b7439cb7ab35c370f682cac7ef9523a)
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 /*
22*32715170SCathy Zhou  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
232b24ab6bSSebastien Roy  */
242b24ab6bSSebastien Roy 
252b24ab6bSSebastien Roy #include <assert.h>
262b24ab6bSSebastien Roy #include <stdio.h>
272b24ab6bSSebastien Roy #include <errno.h>
282b24ab6bSSebastien Roy #include <stdlib.h>
292b24ab6bSSebastien Roy #include <unistd.h>
302b24ab6bSSebastien Roy #include <sys/types.h>
312b24ab6bSSebastien Roy #include <fcntl.h>
322b24ab6bSSebastien Roy #include <stropts.h>
332b24ab6bSSebastien Roy #include <string.h>
342b24ab6bSSebastien Roy #include <netdb.h>
352b24ab6bSSebastien Roy #include <sys/conf.h>
362b24ab6bSSebastien Roy #include <sys/socket.h>
372b24ab6bSSebastien Roy #include <netinet/in.h>
382b24ab6bSSebastien Roy #include <inet/iptun.h>
392b24ab6bSSebastien Roy #include <sys/dls.h>
402b24ab6bSSebastien Roy #include <libdlpi.h>
412b24ab6bSSebastien Roy #include <libdladm_impl.h>
422b24ab6bSSebastien Roy #include <libdllink.h>
432b24ab6bSSebastien Roy #include <libdliptun.h>
442b24ab6bSSebastien Roy 
452b24ab6bSSebastien Roy /*
462b24ab6bSSebastien Roy  * IP Tunneling Administration Library.
472b24ab6bSSebastien Roy  * This library is used by dladm(1M) and to configure IP tunnel links.
482b24ab6bSSebastien Roy  */
492b24ab6bSSebastien Roy 
502b24ab6bSSebastien Roy #define	IPTUN_CONF_TYPE		"type"
512b24ab6bSSebastien Roy #define	IPTUN_CONF_LADDR	"laddr"
522b24ab6bSSebastien Roy #define	IPTUN_CONF_RADDR	"raddr"
532b24ab6bSSebastien Roy 
542b24ab6bSSebastien Roy /*
552b24ab6bSSebastien Roy  * If IPTUN_CREATE and IPTUN_MODIFY include IPsec policy and IPsec hasn't
562b24ab6bSSebastien Roy  * loaded yet, the ioctls may return EAGAIN.  We try the ioctl
572b24ab6bSSebastien Roy  * IPTUN_IOCTL_ATTEMPT_LIMIT times and wait IPTUN_IOCTL_ATTEMPT_INTERVAL
582b24ab6bSSebastien Roy  * microseconds between attempts.
592b24ab6bSSebastien Roy  */
602b24ab6bSSebastien Roy #define	IPTUN_IOCTL_ATTEMPT_LIMIT	3
612b24ab6bSSebastien Roy #define	IPTUN_IOCTL_ATTEMPT_INTERVAL	10000
622b24ab6bSSebastien Roy 
632b24ab6bSSebastien Roy dladm_status_t
642b24ab6bSSebastien Roy i_iptun_ioctl(dladm_handle_t handle, int cmd, void *dp)
652b24ab6bSSebastien Roy {
662b24ab6bSSebastien Roy 	dladm_status_t	status = DLADM_STATUS_OK;
672b24ab6bSSebastien Roy 	uint_t		attempt;
682b24ab6bSSebastien Roy 
692b24ab6bSSebastien Roy 	for (attempt = 0; attempt < IPTUN_IOCTL_ATTEMPT_LIMIT; attempt++) {
702b24ab6bSSebastien Roy 		if (attempt != 0)
712b24ab6bSSebastien Roy 			(void) usleep(IPTUN_IOCTL_ATTEMPT_INTERVAL);
722b24ab6bSSebastien Roy 		status = (ioctl(dladm_dld_fd(handle), cmd, dp) == 0) ?
732b24ab6bSSebastien Roy 		    DLADM_STATUS_OK : dladm_errno2status(errno);
742b24ab6bSSebastien Roy 		if (status != DLADM_STATUS_TRYAGAIN)
752b24ab6bSSebastien Roy 			break;
762b24ab6bSSebastien Roy 	}
772b24ab6bSSebastien Roy 	return (status);
782b24ab6bSSebastien Roy }
792b24ab6bSSebastien Roy 
802b24ab6bSSebastien Roy /*
812b24ab6bSSebastien Roy  * Given tunnel paramaters as supplied by a library consumer, fill in kernel
822b24ab6bSSebastien Roy  * parameters to be passed down to the iptun control device.
832b24ab6bSSebastien Roy  */
842b24ab6bSSebastien Roy static dladm_status_t
852b24ab6bSSebastien Roy i_iptun_kparams(dladm_handle_t handle, const iptun_params_t *params,
862b24ab6bSSebastien Roy     iptun_kparams_t *ik)
872b24ab6bSSebastien Roy {
882b24ab6bSSebastien Roy 	dladm_status_t	status;
892b24ab6bSSebastien Roy 	struct addrinfo	*ai, hints;
902b24ab6bSSebastien Roy 	iptun_kparams_t	tmpik;
912b24ab6bSSebastien Roy 	iptun_type_t	iptuntype = IPTUN_TYPE_UNKNOWN;
922b24ab6bSSebastien Roy 
932b24ab6bSSebastien Roy 	(void) memset(ik, 0, sizeof (*ik));
942b24ab6bSSebastien Roy 
952b24ab6bSSebastien Roy 	ik->iptun_kparam_linkid = params->iptun_param_linkid;
962b24ab6bSSebastien Roy 
972b24ab6bSSebastien Roy 	if (params->iptun_param_flags & IPTUN_PARAM_TYPE) {
982b24ab6bSSebastien Roy 		ik->iptun_kparam_type = iptuntype = params->iptun_param_type;
992b24ab6bSSebastien Roy 		ik->iptun_kparam_flags |= IPTUN_KPARAM_TYPE;
1002b24ab6bSSebastien Roy 	}
1012b24ab6bSSebastien Roy 
1022b24ab6bSSebastien Roy 	if (params->iptun_param_flags & (IPTUN_PARAM_LADDR|IPTUN_PARAM_RADDR)) {
1032b24ab6bSSebastien Roy 		if (iptuntype == IPTUN_TYPE_UNKNOWN) {
1042b24ab6bSSebastien Roy 			/*
1052b24ab6bSSebastien Roy 			 * We need to get the type of this existing tunnel in
1062b24ab6bSSebastien Roy 			 * order to validate and/or look up the right kind of
1072b24ab6bSSebastien Roy 			 * IP address.
1082b24ab6bSSebastien Roy 			 */
1092b24ab6bSSebastien Roy 			tmpik.iptun_kparam_linkid = params->iptun_param_linkid;
1102b24ab6bSSebastien Roy 			status = i_iptun_ioctl(handle, IPTUN_INFO, &tmpik);
1112b24ab6bSSebastien Roy 			if (status != DLADM_STATUS_OK)
1122b24ab6bSSebastien Roy 				return (status);
1132b24ab6bSSebastien Roy 			iptuntype = tmpik.iptun_kparam_type;
1142b24ab6bSSebastien Roy 		}
1152b24ab6bSSebastien Roy 
1162b24ab6bSSebastien Roy 		(void) memset(&hints, 0, sizeof (hints));
1172b24ab6bSSebastien Roy 		switch (iptuntype) {
1182b24ab6bSSebastien Roy 		case IPTUN_TYPE_IPV4:
1192b24ab6bSSebastien Roy 		case IPTUN_TYPE_6TO4:
1202b24ab6bSSebastien Roy 			hints.ai_family = AF_INET;
1212b24ab6bSSebastien Roy 			break;
1222b24ab6bSSebastien Roy 		case IPTUN_TYPE_IPV6:
1232b24ab6bSSebastien Roy 			hints.ai_family = AF_INET6;
1242b24ab6bSSebastien Roy 			break;
1252b24ab6bSSebastien Roy 		}
1262b24ab6bSSebastien Roy 	}
1272b24ab6bSSebastien Roy 
1282b24ab6bSSebastien Roy 	if (params->iptun_param_flags & IPTUN_PARAM_LADDR) {
1292b24ab6bSSebastien Roy 		if (getaddrinfo(params->iptun_param_laddr, NULL, &hints, &ai) !=
1302b24ab6bSSebastien Roy 		    0)
1312b24ab6bSSebastien Roy 			return (DLADM_STATUS_BADIPTUNLADDR);
1322b24ab6bSSebastien Roy 		if (ai->ai_next != NULL) {
1332b24ab6bSSebastien Roy 			freeaddrinfo(ai);
1342b24ab6bSSebastien Roy 			return (DLADM_STATUS_BADIPTUNLADDR);
1352b24ab6bSSebastien Roy 		}
1362b24ab6bSSebastien Roy 		(void) memcpy(&ik->iptun_kparam_laddr, ai->ai_addr,
1372b24ab6bSSebastien Roy 		    ai->ai_addrlen);
1382b24ab6bSSebastien Roy 		ik->iptun_kparam_flags |= IPTUN_KPARAM_LADDR;
1392b24ab6bSSebastien Roy 		freeaddrinfo(ai);
1402b24ab6bSSebastien Roy 	}
1412b24ab6bSSebastien Roy 
1422b24ab6bSSebastien Roy 	if (params->iptun_param_flags & IPTUN_PARAM_RADDR) {
1432b24ab6bSSebastien Roy 		if (getaddrinfo(params->iptun_param_raddr, NULL, &hints, &ai) !=
1442b24ab6bSSebastien Roy 		    0)
1452b24ab6bSSebastien Roy 			return (DLADM_STATUS_BADIPTUNRADDR);
1462b24ab6bSSebastien Roy 		if (ai->ai_next != NULL) {
1472b24ab6bSSebastien Roy 			freeaddrinfo(ai);
1482b24ab6bSSebastien Roy 			return (DLADM_STATUS_BADIPTUNRADDR);
1492b24ab6bSSebastien Roy 		}
1502b24ab6bSSebastien Roy 		(void) memcpy(&ik->iptun_kparam_raddr, ai->ai_addr,
1512b24ab6bSSebastien Roy 		    ai->ai_addrlen);
1522b24ab6bSSebastien Roy 		ik->iptun_kparam_flags |= IPTUN_KPARAM_RADDR;
1532b24ab6bSSebastien Roy 		freeaddrinfo(ai);
1542b24ab6bSSebastien Roy 	}
1552b24ab6bSSebastien Roy 
1562b24ab6bSSebastien Roy 	if (params->iptun_param_flags & IPTUN_PARAM_SECINFO) {
1572b24ab6bSSebastien Roy 		ik->iptun_kparam_secinfo = params->iptun_param_secinfo;
1582b24ab6bSSebastien Roy 		ik->iptun_kparam_flags |= IPTUN_KPARAM_SECINFO;
1592b24ab6bSSebastien Roy 	}
1602b24ab6bSSebastien Roy 
1612b24ab6bSSebastien Roy 	return (DLADM_STATUS_OK);
1622b24ab6bSSebastien Roy }
1632b24ab6bSSebastien Roy 
1642b24ab6bSSebastien Roy /*
1652b24ab6bSSebastien Roy  * The inverse of i_iptun_kparams().  Given kernel tunnel paramaters as
1662b24ab6bSSebastien Roy  * returned from an IPTUN_INFO ioctl, fill in tunnel parameters.
1672b24ab6bSSebastien Roy  */
1682b24ab6bSSebastien Roy static dladm_status_t
1692b24ab6bSSebastien Roy i_iptun_params(const iptun_kparams_t *ik, iptun_params_t *params)
1702b24ab6bSSebastien Roy {
1712b24ab6bSSebastien Roy 	socklen_t salen;
1722b24ab6bSSebastien Roy 
1732b24ab6bSSebastien Roy 	(void) memset(params, 0, sizeof (*params));
1742b24ab6bSSebastien Roy 
1752b24ab6bSSebastien Roy 	params->iptun_param_linkid = ik->iptun_kparam_linkid;
1762b24ab6bSSebastien Roy 
1772b24ab6bSSebastien Roy 	if (ik->iptun_kparam_flags & IPTUN_KPARAM_TYPE) {
1782b24ab6bSSebastien Roy 		params->iptun_param_type = ik->iptun_kparam_type;
1792b24ab6bSSebastien Roy 		params->iptun_param_flags |= IPTUN_PARAM_TYPE;
1802b24ab6bSSebastien Roy 	}
1812b24ab6bSSebastien Roy 
1822b24ab6bSSebastien Roy 	if (ik->iptun_kparam_flags & IPTUN_KPARAM_LADDR) {
1832b24ab6bSSebastien Roy 		salen = ik->iptun_kparam_laddr.ss_family == AF_INET ?
1842b24ab6bSSebastien Roy 		    sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6);
1852b24ab6bSSebastien Roy 		if (getnameinfo((const struct sockaddr *)
1862b24ab6bSSebastien Roy 		    &ik->iptun_kparam_laddr, salen, params->iptun_param_laddr,
1872b24ab6bSSebastien Roy 		    sizeof (params->iptun_param_laddr), NULL, 0,
1882b24ab6bSSebastien Roy 		    NI_NUMERICHOST) != 0) {
1892b24ab6bSSebastien Roy 			return (DLADM_STATUS_BADIPTUNLADDR);
1902b24ab6bSSebastien Roy 		}
1912b24ab6bSSebastien Roy 		params->iptun_param_flags |= IPTUN_PARAM_LADDR;
1922b24ab6bSSebastien Roy 	}
1932b24ab6bSSebastien Roy 
1942b24ab6bSSebastien Roy 	if (ik->iptun_kparam_flags & IPTUN_KPARAM_RADDR) {
1952b24ab6bSSebastien Roy 		salen = ik->iptun_kparam_raddr.ss_family == AF_INET ?
1962b24ab6bSSebastien Roy 		    sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6);
1972b24ab6bSSebastien Roy 		if (getnameinfo((const struct sockaddr *)
1982b24ab6bSSebastien Roy 		    &ik->iptun_kparam_raddr, salen, params->iptun_param_raddr,
1992b24ab6bSSebastien Roy 		    sizeof (params->iptun_param_raddr), NULL, 0,
2002b24ab6bSSebastien Roy 		    NI_NUMERICHOST) != 0) {
2012b24ab6bSSebastien Roy 			return (DLADM_STATUS_BADIPTUNRADDR);
2022b24ab6bSSebastien Roy 		}
2032b24ab6bSSebastien Roy 		params->iptun_param_flags |= IPTUN_PARAM_RADDR;
2042b24ab6bSSebastien Roy 	}
2052b24ab6bSSebastien Roy 
2062b24ab6bSSebastien Roy 	if (ik->iptun_kparam_flags & IPTUN_KPARAM_SECINFO) {
2072b24ab6bSSebastien Roy 		params->iptun_param_secinfo = ik->iptun_kparam_secinfo;
2082b24ab6bSSebastien Roy 		params->iptun_param_flags |= IPTUN_PARAM_SECINFO;
2092b24ab6bSSebastien Roy 	}
2102b24ab6bSSebastien Roy 
2112b24ab6bSSebastien Roy 	if (ik->iptun_kparam_flags & IPTUN_KPARAM_IMPLICIT)
2122b24ab6bSSebastien Roy 		params->iptun_param_flags |= IPTUN_PARAM_IMPLICIT;
2132b24ab6bSSebastien Roy 
2142b24ab6bSSebastien Roy 	if (ik->iptun_kparam_flags & IPTUN_KPARAM_IPSECPOL)
2152b24ab6bSSebastien Roy 		params->iptun_param_flags |= IPTUN_PARAM_IPSECPOL;
2162b24ab6bSSebastien Roy 
2172b24ab6bSSebastien Roy 	return (DLADM_STATUS_OK);
2182b24ab6bSSebastien Roy }
2192b24ab6bSSebastien Roy 
2202b24ab6bSSebastien Roy dladm_status_t
2212b24ab6bSSebastien Roy i_iptun_get_sysparams(dladm_handle_t handle, iptun_params_t *params)
2222b24ab6bSSebastien Roy {
2232b24ab6bSSebastien Roy 	dladm_status_t	status = DLADM_STATUS_OK;
2242b24ab6bSSebastien Roy 	iptun_kparams_t	ik;
2252b24ab6bSSebastien Roy 
2262b24ab6bSSebastien Roy 	ik.iptun_kparam_linkid = params->iptun_param_linkid;
2272b24ab6bSSebastien Roy 	status = i_iptun_ioctl(handle, IPTUN_INFO, &ik);
2282b24ab6bSSebastien Roy 	if (status == DLADM_STATUS_OK)
2292b24ab6bSSebastien Roy 		status = i_iptun_params(&ik, params);
2302b24ab6bSSebastien Roy 	return (status);
2312b24ab6bSSebastien Roy }
2322b24ab6bSSebastien Roy 
2332b24ab6bSSebastien Roy /*
2342b24ab6bSSebastien Roy  * Read tunnel parameters from persistent storage.  Note that the tunnel type
2352b24ab6bSSebastien Roy  * is the only thing which must always be in the configuratioh.  All other
2362b24ab6bSSebastien Roy  * parameters (currently the source and destination addresses) may or may not
2372b24ab6bSSebastien Roy  * have been configured, and therefore may not have been set.
2382b24ab6bSSebastien Roy  */
2392b24ab6bSSebastien Roy static dladm_status_t
2402b24ab6bSSebastien Roy i_iptun_get_dbparams(dladm_handle_t handle, iptun_params_t *params)
2412b24ab6bSSebastien Roy {
2422b24ab6bSSebastien Roy 	dladm_status_t		status;
2432b24ab6bSSebastien Roy 	dladm_conf_t		conf;
2442b24ab6bSSebastien Roy 	datalink_class_t	class;
2452b24ab6bSSebastien Roy 	uint64_t		temp;
2462b24ab6bSSebastien Roy 
2472b24ab6bSSebastien Roy 	/* First, make sure that this is an IP tunnel. */
2482b24ab6bSSebastien Roy 	if ((status = dladm_datalink_id2info(handle, params->iptun_param_linkid,
2492b24ab6bSSebastien Roy 	    NULL, &class, NULL, NULL, 0)) != DLADM_STATUS_OK)
2502b24ab6bSSebastien Roy 		return (status);
2512b24ab6bSSebastien Roy 	if (class != DATALINK_CLASS_IPTUN)
2522b24ab6bSSebastien Roy 		return (DLADM_STATUS_LINKINVAL);
2532b24ab6bSSebastien Roy 
254*32715170SCathy Zhou 	if ((status = dladm_getsnap_conf(handle, params->iptun_param_linkid,
255*32715170SCathy Zhou 	    &conf)) != DLADM_STATUS_OK) {
2562b24ab6bSSebastien Roy 		return (status);
257*32715170SCathy Zhou 	}
2582b24ab6bSSebastien Roy 
2592b24ab6bSSebastien Roy 	params->iptun_param_flags = 0;
2602b24ab6bSSebastien Roy 
2612b24ab6bSSebastien Roy 	if ((status = dladm_get_conf_field(handle, conf, IPTUN_CONF_TYPE, &temp,
2622b24ab6bSSebastien Roy 	    sizeof (temp))) != DLADM_STATUS_OK)
2632b24ab6bSSebastien Roy 		goto done;
2642b24ab6bSSebastien Roy 	params->iptun_param_type = (iptun_type_t)temp;
2652b24ab6bSSebastien Roy 	params->iptun_param_flags |= IPTUN_PARAM_TYPE;
2662b24ab6bSSebastien Roy 
2672b24ab6bSSebastien Roy 	if (dladm_get_conf_field(handle, conf, IPTUN_CONF_LADDR,
2682b24ab6bSSebastien Roy 	    params->iptun_param_laddr, sizeof (params->iptun_param_laddr)) ==
2692b24ab6bSSebastien Roy 	    DLADM_STATUS_OK)
2702b24ab6bSSebastien Roy 		params->iptun_param_flags |= IPTUN_PARAM_LADDR;
2712b24ab6bSSebastien Roy 
2722b24ab6bSSebastien Roy 	if (dladm_get_conf_field(handle, conf, IPTUN_CONF_RADDR,
2732b24ab6bSSebastien Roy 	    params->iptun_param_raddr, sizeof (params->iptun_param_raddr)) ==
2742b24ab6bSSebastien Roy 	    DLADM_STATUS_OK)
2752b24ab6bSSebastien Roy 		params->iptun_param_flags |= IPTUN_PARAM_RADDR;
2762b24ab6bSSebastien Roy 
2772b24ab6bSSebastien Roy done:
2782b24ab6bSSebastien Roy 	dladm_destroy_conf(handle, conf);
2792b24ab6bSSebastien Roy 	return (status);
2802b24ab6bSSebastien Roy }
2812b24ab6bSSebastien Roy 
2822b24ab6bSSebastien Roy static dladm_status_t
2832b24ab6bSSebastien Roy i_iptun_create_sys(dladm_handle_t handle, iptun_params_t *params)
2842b24ab6bSSebastien Roy {
2852b24ab6bSSebastien Roy 	iptun_kparams_t	ik;
2862b24ab6bSSebastien Roy 	dladm_status_t	status = DLADM_STATUS_OK;
2872b24ab6bSSebastien Roy 
2882b24ab6bSSebastien Roy 	/* The tunnel type is required for creation. */
2892b24ab6bSSebastien Roy 	if (!(params->iptun_param_flags & IPTUN_PARAM_TYPE))
2902b24ab6bSSebastien Roy 		return (DLADM_STATUS_IPTUNTYPEREQD);
2912b24ab6bSSebastien Roy 
2922b24ab6bSSebastien Roy 	if ((status = i_iptun_kparams(handle, params, &ik)) == DLADM_STATUS_OK)
2932b24ab6bSSebastien Roy 		status = i_iptun_ioctl(handle, IPTUN_CREATE, &ik);
2942b24ab6bSSebastien Roy 	return (status);
2952b24ab6bSSebastien Roy }
2962b24ab6bSSebastien Roy 
2972b24ab6bSSebastien Roy static dladm_status_t
2982b24ab6bSSebastien Roy i_iptun_create_db(dladm_handle_t handle, const char *name,
2992b24ab6bSSebastien Roy     iptun_params_t *params, uint32_t media)
3002b24ab6bSSebastien Roy {
3012b24ab6bSSebastien Roy 	dladm_conf_t	conf;
3022b24ab6bSSebastien Roy 	dladm_status_t	status;
3032b24ab6bSSebastien Roy 	uint64_t	storage;
3042b24ab6bSSebastien Roy 
3052b24ab6bSSebastien Roy 	status = dladm_create_conf(handle, name, params->iptun_param_linkid,
3062b24ab6bSSebastien Roy 	    DATALINK_CLASS_IPTUN, media, &conf);
3072b24ab6bSSebastien Roy 	if (status != DLADM_STATUS_OK)
3082b24ab6bSSebastien Roy 		return (status);
3092b24ab6bSSebastien Roy 
3102b24ab6bSSebastien Roy 	assert(params->iptun_param_flags & IPTUN_PARAM_TYPE);
3112b24ab6bSSebastien Roy 	storage = params->iptun_param_type;
3122b24ab6bSSebastien Roy 	status = dladm_set_conf_field(handle, conf, IPTUN_CONF_TYPE,
3132b24ab6bSSebastien Roy 	    DLADM_TYPE_UINT64, &storage);
3142b24ab6bSSebastien Roy 	if (status != DLADM_STATUS_OK)
3152b24ab6bSSebastien Roy 		goto done;
3162b24ab6bSSebastien Roy 
3172b24ab6bSSebastien Roy 	if (params->iptun_param_flags & IPTUN_PARAM_LADDR) {
3182b24ab6bSSebastien Roy 		status = dladm_set_conf_field(handle, conf, IPTUN_CONF_LADDR,
3192b24ab6bSSebastien Roy 		    DLADM_TYPE_STR, params->iptun_param_laddr);
3202b24ab6bSSebastien Roy 		if (status != DLADM_STATUS_OK)
3212b24ab6bSSebastien Roy 			goto done;
3222b24ab6bSSebastien Roy 	}
3232b24ab6bSSebastien Roy 
3242b24ab6bSSebastien Roy 	if (params->iptun_param_flags & IPTUN_PARAM_RADDR) {
3252b24ab6bSSebastien Roy 		status = dladm_set_conf_field(handle, conf, IPTUN_CONF_RADDR,
3262b24ab6bSSebastien Roy 		    DLADM_TYPE_STR, params->iptun_param_raddr);
3272b24ab6bSSebastien Roy 		if (status != DLADM_STATUS_OK)
3282b24ab6bSSebastien Roy 			goto done;
3292b24ab6bSSebastien Roy 	}
3302b24ab6bSSebastien Roy 
3312b24ab6bSSebastien Roy 	status = dladm_write_conf(handle, conf);
3322b24ab6bSSebastien Roy 
3332b24ab6bSSebastien Roy done:
3342b24ab6bSSebastien Roy 	dladm_destroy_conf(handle, conf);
3352b24ab6bSSebastien Roy 	return (status);
3362b24ab6bSSebastien Roy }
3372b24ab6bSSebastien Roy 
3382b24ab6bSSebastien Roy static dladm_status_t
3392b24ab6bSSebastien Roy i_iptun_delete_sys(dladm_handle_t handle, datalink_id_t linkid)
3402b24ab6bSSebastien Roy {
3412b24ab6bSSebastien Roy 	dladm_status_t status;
3422b24ab6bSSebastien Roy 
3432b24ab6bSSebastien Roy 	status = i_iptun_ioctl(handle, IPTUN_DELETE, &linkid);
3442b24ab6bSSebastien Roy 	if (status != DLADM_STATUS_OK)
3452b24ab6bSSebastien Roy 		return (status);
3462b24ab6bSSebastien Roy 	(void) dladm_destroy_datalink_id(handle, linkid, DLADM_OPT_ACTIVE);
3472b24ab6bSSebastien Roy 	return (DLADM_STATUS_OK);
3482b24ab6bSSebastien Roy }
3492b24ab6bSSebastien Roy 
3502b24ab6bSSebastien Roy static dladm_status_t
3512b24ab6bSSebastien Roy i_iptun_modify_sys(dladm_handle_t handle, const iptun_params_t *params)
3522b24ab6bSSebastien Roy {
3532b24ab6bSSebastien Roy 	iptun_kparams_t	ik;
3542b24ab6bSSebastien Roy 	dladm_status_t	status;
3552b24ab6bSSebastien Roy 
3562b24ab6bSSebastien Roy 	if ((status = i_iptun_kparams(handle, params, &ik)) == DLADM_STATUS_OK)
3572b24ab6bSSebastien Roy 		status = i_iptun_ioctl(handle, IPTUN_MODIFY, &ik);
3582b24ab6bSSebastien Roy 	return (status);
3592b24ab6bSSebastien Roy }
3602b24ab6bSSebastien Roy 
3612b24ab6bSSebastien Roy static dladm_status_t
3622b24ab6bSSebastien Roy i_iptun_modify_db(dladm_handle_t handle, const iptun_params_t *params)
3632b24ab6bSSebastien Roy {
3642b24ab6bSSebastien Roy 	dladm_conf_t	conf;
3652b24ab6bSSebastien Roy 	dladm_status_t	status;
3662b24ab6bSSebastien Roy 
3672b24ab6bSSebastien Roy 	assert(params->iptun_param_flags &
3682b24ab6bSSebastien Roy 	    (IPTUN_PARAM_LADDR|IPTUN_PARAM_RADDR));
3692b24ab6bSSebastien Roy 
3702b24ab6bSSebastien Roy 	/*
3712b24ab6bSSebastien Roy 	 * The only parameters that can be modified persistently are the local
3722b24ab6bSSebastien Roy 	 * and remote addresses.
3732b24ab6bSSebastien Roy 	 */
3742b24ab6bSSebastien Roy 	if (params->iptun_param_flags & ~(IPTUN_PARAM_LADDR|IPTUN_PARAM_RADDR))
3752b24ab6bSSebastien Roy 		return (DLADM_STATUS_BADARG);
3762b24ab6bSSebastien Roy 
377*32715170SCathy Zhou 	status = dladm_open_conf(handle, params->iptun_param_linkid, &conf);
3782b24ab6bSSebastien Roy 	if (status != DLADM_STATUS_OK)
3792b24ab6bSSebastien Roy 		return (status);
3802b24ab6bSSebastien Roy 
3812b24ab6bSSebastien Roy 	if (params->iptun_param_flags & IPTUN_PARAM_LADDR) {
3822b24ab6bSSebastien Roy 		status = dladm_set_conf_field(handle, conf, IPTUN_CONF_LADDR,
3832b24ab6bSSebastien Roy 		    DLADM_TYPE_STR, (void *)params->iptun_param_laddr);
3842b24ab6bSSebastien Roy 		if (status != DLADM_STATUS_OK)
3852b24ab6bSSebastien Roy 			goto done;
3862b24ab6bSSebastien Roy 	}
3872b24ab6bSSebastien Roy 
3882b24ab6bSSebastien Roy 	if (params->iptun_param_flags & IPTUN_PARAM_RADDR) {
3892b24ab6bSSebastien Roy 		status = dladm_set_conf_field(handle, conf, IPTUN_CONF_RADDR,
3902b24ab6bSSebastien Roy 		    DLADM_TYPE_STR, (void *)params->iptun_param_raddr);
3912b24ab6bSSebastien Roy 		if (status != DLADM_STATUS_OK)
3922b24ab6bSSebastien Roy 			goto done;
3932b24ab6bSSebastien Roy 	}
3942b24ab6bSSebastien Roy 
3952b24ab6bSSebastien Roy 	status = dladm_write_conf(handle, conf);
3962b24ab6bSSebastien Roy 
3972b24ab6bSSebastien Roy done:
3982b24ab6bSSebastien Roy 	dladm_destroy_conf(handle, conf);
3992b24ab6bSSebastien Roy 	return (status);
4002b24ab6bSSebastien Roy }
4012b24ab6bSSebastien Roy 
4022b24ab6bSSebastien Roy dladm_status_t
4032b24ab6bSSebastien Roy dladm_iptun_create(dladm_handle_t handle, const char *name,
4042b24ab6bSSebastien Roy     iptun_params_t *params, uint32_t flags)
4052b24ab6bSSebastien Roy {
4062b24ab6bSSebastien Roy 	dladm_status_t	status;
4072b24ab6bSSebastien Roy 	uint32_t	linkmgmt_flags = flags;
4082b24ab6bSSebastien Roy 	uint32_t	media;
4092b24ab6bSSebastien Roy 
4102b24ab6bSSebastien Roy 	if (!(params->iptun_param_flags & IPTUN_PARAM_TYPE))
4112b24ab6bSSebastien Roy 		return (DLADM_STATUS_IPTUNTYPEREQD);
4122b24ab6bSSebastien Roy 
4132b24ab6bSSebastien Roy 	switch (params->iptun_param_type) {
4142b24ab6bSSebastien Roy 	case IPTUN_TYPE_IPV4:
4152b24ab6bSSebastien Roy 		media = DL_IPV4;
4162b24ab6bSSebastien Roy 		break;
4172b24ab6bSSebastien Roy 	case IPTUN_TYPE_IPV6:
4182b24ab6bSSebastien Roy 		media = DL_IPV6;
4192b24ab6bSSebastien Roy 		break;
4202b24ab6bSSebastien Roy 	case IPTUN_TYPE_6TO4:
4212b24ab6bSSebastien Roy 		media = DL_6TO4;
4222b24ab6bSSebastien Roy 		break;
4232b24ab6bSSebastien Roy 	default:
4242b24ab6bSSebastien Roy 		return (DLADM_STATUS_IPTUNTYPE);
4252b24ab6bSSebastien Roy 	}
4262b24ab6bSSebastien Roy 
4272b24ab6bSSebastien Roy 	status = dladm_create_datalink_id(handle, name, DATALINK_CLASS_IPTUN,
4282b24ab6bSSebastien Roy 	    media, linkmgmt_flags, &params->iptun_param_linkid);
4292b24ab6bSSebastien Roy 	if (status != DLADM_STATUS_OK)
4302b24ab6bSSebastien Roy 		return (status);
4312b24ab6bSSebastien Roy 
4322b24ab6bSSebastien Roy 	if (flags & DLADM_OPT_PERSIST) {
4332b24ab6bSSebastien Roy 		status = i_iptun_create_db(handle, name, params, media);
4342b24ab6bSSebastien Roy 		if (status != DLADM_STATUS_OK)
4352b24ab6bSSebastien Roy 			goto done;
4362b24ab6bSSebastien Roy 	}
4372b24ab6bSSebastien Roy 
4382b24ab6bSSebastien Roy 	if (flags & DLADM_OPT_ACTIVE) {
4392b24ab6bSSebastien Roy 		status = i_iptun_create_sys(handle, params);
4402b24ab6bSSebastien Roy 		if (status != DLADM_STATUS_OK && (flags & DLADM_OPT_PERSIST)) {
4412b24ab6bSSebastien Roy 			(void) dladm_remove_conf(handle,
4422b24ab6bSSebastien Roy 			    params->iptun_param_linkid);
4432b24ab6bSSebastien Roy 		}
4442b24ab6bSSebastien Roy 	}
4452b24ab6bSSebastien Roy 
4462b24ab6bSSebastien Roy done:
4472b24ab6bSSebastien Roy 	if (status != DLADM_STATUS_OK) {
4482b24ab6bSSebastien Roy 		(void) dladm_destroy_datalink_id(handle,
4492b24ab6bSSebastien Roy 		    params->iptun_param_linkid, flags);
4502b24ab6bSSebastien Roy 	}
4512b24ab6bSSebastien Roy 	return (status);
4522b24ab6bSSebastien Roy }
4532b24ab6bSSebastien Roy 
4542b24ab6bSSebastien Roy dladm_status_t
4552b24ab6bSSebastien Roy dladm_iptun_delete(dladm_handle_t handle, datalink_id_t linkid, uint32_t flags)
4562b24ab6bSSebastien Roy {
4572b24ab6bSSebastien Roy 	dladm_status_t		status;
4582b24ab6bSSebastien Roy 	datalink_class_t	class;
4592b24ab6bSSebastien Roy 
4602b24ab6bSSebastien Roy 	/* First, make sure that this is an IP tunnel. */
4612b24ab6bSSebastien Roy 	if ((status = dladm_datalink_id2info(handle, linkid, NULL, &class, NULL,
4622b24ab6bSSebastien Roy 	    NULL, 0)) != DLADM_STATUS_OK)
4632b24ab6bSSebastien Roy 		return (status);
4642b24ab6bSSebastien Roy 	if (class != DATALINK_CLASS_IPTUN)
4652b24ab6bSSebastien Roy 		return (DLADM_STATUS_LINKINVAL);
4662b24ab6bSSebastien Roy 
4672b24ab6bSSebastien Roy 	if (flags & DLADM_OPT_ACTIVE) {
4682b24ab6bSSebastien Roy 		/*
4692b24ab6bSSebastien Roy 		 * Note that if i_iptun_delete_sys() fails with
4702b24ab6bSSebastien Roy 		 * DLADM_STATUS_NOTFOUND and the caller also wishes to delete
4712b24ab6bSSebastien Roy 		 * the persistent configuration, we still fall through to the
4722b24ab6bSSebastien Roy 		 * DLADM_OPT_PERSIST case in case the tunnel only exists
4732b24ab6bSSebastien Roy 		 * persistently.
4742b24ab6bSSebastien Roy 		 */
4752b24ab6bSSebastien Roy 		status = i_iptun_delete_sys(handle, linkid);
4762b24ab6bSSebastien Roy 		if (status != DLADM_STATUS_OK &&
4772b24ab6bSSebastien Roy 		    (status != DLADM_STATUS_NOTFOUND ||
4782b24ab6bSSebastien Roy 		    !(flags & DLADM_OPT_PERSIST)))
4792b24ab6bSSebastien Roy 			return (status);
4802b24ab6bSSebastien Roy 	}
4812b24ab6bSSebastien Roy 
4822b24ab6bSSebastien Roy 	if (flags & DLADM_OPT_PERSIST) {
4832b24ab6bSSebastien Roy 		(void) dladm_remove_conf(handle, linkid);
4842b24ab6bSSebastien Roy 		(void) dladm_destroy_datalink_id(handle, linkid,
4852b24ab6bSSebastien Roy 		    DLADM_OPT_PERSIST);
4862b24ab6bSSebastien Roy 	}
4872b24ab6bSSebastien Roy 	return (DLADM_STATUS_OK);
4882b24ab6bSSebastien Roy }
4892b24ab6bSSebastien Roy 
4902b24ab6bSSebastien Roy dladm_status_t
4912b24ab6bSSebastien Roy dladm_iptun_modify(dladm_handle_t handle, const iptun_params_t *params,
4922b24ab6bSSebastien Roy     uint32_t flags)
4932b24ab6bSSebastien Roy {
4942b24ab6bSSebastien Roy 	dladm_status_t	status = DLADM_STATUS_OK;
4952b24ab6bSSebastien Roy 	iptun_params_t	old_params;
4962b24ab6bSSebastien Roy 
4972b24ab6bSSebastien Roy 	/*
4982b24ab6bSSebastien Roy 	 * We can only modify the tunnel source, tunnel destination, or IPsec
4992b24ab6bSSebastien Roy 	 * policy.
5002b24ab6bSSebastien Roy 	 */
5012b24ab6bSSebastien Roy 	if (!(params->iptun_param_flags &
5022b24ab6bSSebastien Roy 	    (IPTUN_PARAM_LADDR|IPTUN_PARAM_RADDR|IPTUN_PARAM_SECINFO)))
5032b24ab6bSSebastien Roy 		return (DLADM_STATUS_BADARG);
5042b24ab6bSSebastien Roy 
5052b24ab6bSSebastien Roy 	if (flags & DLADM_OPT_PERSIST) {
5062b24ab6bSSebastien Roy 		/*
5072b24ab6bSSebastien Roy 		 * Before we change the database, save the old configuration
5082b24ab6bSSebastien Roy 		 * so that we can revert back if an error occurs.
5092b24ab6bSSebastien Roy 		 */
5102b24ab6bSSebastien Roy 		old_params.iptun_param_linkid = params->iptun_param_linkid;
5112b24ab6bSSebastien Roy 		status = i_iptun_get_dbparams(handle, &old_params);
5122b24ab6bSSebastien Roy 		if (status != DLADM_STATUS_OK)
5132b24ab6bSSebastien Roy 			return (status);
5142b24ab6bSSebastien Roy 		/* we'll only need to revert the parameters being modified */
5152b24ab6bSSebastien Roy 		old_params.iptun_param_flags = params->iptun_param_flags;
5162b24ab6bSSebastien Roy 
5172b24ab6bSSebastien Roy 		status = i_iptun_modify_db(handle, params);
5182b24ab6bSSebastien Roy 		if (status != DLADM_STATUS_OK)
5192b24ab6bSSebastien Roy 			return (status);
5202b24ab6bSSebastien Roy 	}
5212b24ab6bSSebastien Roy 
5222b24ab6bSSebastien Roy 	if (flags & DLADM_OPT_ACTIVE) {
5232b24ab6bSSebastien Roy 		status = i_iptun_modify_sys(handle, params);
5242b24ab6bSSebastien Roy 		if (status != DLADM_STATUS_OK && (flags & DLADM_OPT_PERSIST)) {
5252b24ab6bSSebastien Roy 			(void) i_iptun_modify_db(handle, &old_params);
5262b24ab6bSSebastien Roy 		}
5272b24ab6bSSebastien Roy 	}
5282b24ab6bSSebastien Roy 
5292b24ab6bSSebastien Roy 	return (status);
5302b24ab6bSSebastien Roy }
5312b24ab6bSSebastien Roy 
5322b24ab6bSSebastien Roy dladm_status_t
5332b24ab6bSSebastien Roy dladm_iptun_getparams(dladm_handle_t handle, iptun_params_t *params,
5342b24ab6bSSebastien Roy     uint32_t flags)
5352b24ab6bSSebastien Roy {
5362b24ab6bSSebastien Roy 	if (flags == DLADM_OPT_ACTIVE)
5372b24ab6bSSebastien Roy 		return (i_iptun_get_sysparams(handle, params));
5382b24ab6bSSebastien Roy 	else if (flags == DLADM_OPT_PERSIST)
5392b24ab6bSSebastien Roy 		return (i_iptun_get_dbparams(handle, params));
5402b24ab6bSSebastien Roy 	else
5412b24ab6bSSebastien Roy 		return (DLADM_STATUS_BADARG);
5422b24ab6bSSebastien Roy }
5432b24ab6bSSebastien Roy 
5442b24ab6bSSebastien Roy static int
5452b24ab6bSSebastien Roy i_iptun_up(dladm_handle_t handle, datalink_id_t linkid, void *arg)
5462b24ab6bSSebastien Roy {
5472b24ab6bSSebastien Roy 	dladm_status_t	*statusp = arg;
5482b24ab6bSSebastien Roy 	dladm_status_t	status;
5492b24ab6bSSebastien Roy 	iptun_params_t	params;
5502b24ab6bSSebastien Roy 	boolean_t	id_up = B_FALSE;
5512b24ab6bSSebastien Roy 
5522b24ab6bSSebastien Roy 	status = dladm_up_datalink_id(handle, linkid);
5532b24ab6bSSebastien Roy 	if (status != DLADM_STATUS_OK)
5542b24ab6bSSebastien Roy 		goto done;
5552b24ab6bSSebastien Roy 	id_up = B_TRUE;
5562b24ab6bSSebastien Roy 
5572b24ab6bSSebastien Roy 	(void) memset(&params, 0, sizeof (params));
5582b24ab6bSSebastien Roy 
5592b24ab6bSSebastien Roy 	params.iptun_param_linkid = linkid;
5602b24ab6bSSebastien Roy 	if ((status = i_iptun_get_dbparams(handle, &params)) == DLADM_STATUS_OK)
5612b24ab6bSSebastien Roy 		status = i_iptun_create_sys(handle, &params);
5622b24ab6bSSebastien Roy done:
5632b24ab6bSSebastien Roy 	if (statusp != NULL)
5642b24ab6bSSebastien Roy 		*statusp = status;
5652b24ab6bSSebastien Roy 	if (status != DLADM_STATUS_OK && id_up) {
5662b24ab6bSSebastien Roy 		(void) dladm_destroy_datalink_id(handle, linkid,
5672b24ab6bSSebastien Roy 		    DLADM_OPT_ACTIVE);
5682b24ab6bSSebastien Roy 	}
5692b24ab6bSSebastien Roy 	return (DLADM_WALK_CONTINUE);
5702b24ab6bSSebastien Roy }
5712b24ab6bSSebastien Roy 
5722b24ab6bSSebastien Roy static int
5732b24ab6bSSebastien Roy i_iptun_down(dladm_handle_t handle, datalink_id_t linkid, void *arg)
5742b24ab6bSSebastien Roy {
5752b24ab6bSSebastien Roy 	dladm_status_t	*statusp = arg;
5762b24ab6bSSebastien Roy 	dladm_status_t	status;
5772b24ab6bSSebastien Roy 
5782b24ab6bSSebastien Roy 	status = i_iptun_delete_sys(handle, linkid);
5792b24ab6bSSebastien Roy 	if (statusp != NULL)
5802b24ab6bSSebastien Roy 		*statusp = status;
5812b24ab6bSSebastien Roy 	return (DLADM_WALK_CONTINUE);
5822b24ab6bSSebastien Roy }
5832b24ab6bSSebastien Roy 
5842b24ab6bSSebastien Roy /* ARGSUSED */
5852b24ab6bSSebastien Roy dladm_status_t
5862b24ab6bSSebastien Roy dladm_iptun_up(dladm_handle_t handle, datalink_id_t linkid)
5872b24ab6bSSebastien Roy {
5882b24ab6bSSebastien Roy 	dladm_status_t status = DLADM_STATUS_OK;
5892b24ab6bSSebastien Roy 
5902b24ab6bSSebastien Roy 	if (linkid == DATALINK_ALL_LINKID) {
5912b24ab6bSSebastien Roy 		(void) dladm_walk_datalink_id(i_iptun_up, handle, NULL,
5922b24ab6bSSebastien Roy 		    DATALINK_CLASS_IPTUN, DATALINK_ANY_MEDIATYPE,
5932b24ab6bSSebastien Roy 		    DLADM_OPT_PERSIST);
5942b24ab6bSSebastien Roy 	} else {
5952b24ab6bSSebastien Roy 		(void) i_iptun_up(handle, linkid, &status);
5962b24ab6bSSebastien Roy 	}
5972b24ab6bSSebastien Roy 	return (status);
5982b24ab6bSSebastien Roy }
5992b24ab6bSSebastien Roy 
6002b24ab6bSSebastien Roy dladm_status_t
6012b24ab6bSSebastien Roy dladm_iptun_down(dladm_handle_t handle, datalink_id_t linkid)
6022b24ab6bSSebastien Roy {
6032b24ab6bSSebastien Roy 	dladm_status_t status = DLADM_STATUS_OK;
6042b24ab6bSSebastien Roy 
6052b24ab6bSSebastien Roy 	if (linkid == DATALINK_ALL_LINKID) {
6062b24ab6bSSebastien Roy 		(void) dladm_walk_datalink_id(i_iptun_down, handle, NULL,
6072b24ab6bSSebastien Roy 		    DATALINK_CLASS_IPTUN, DATALINK_ANY_MEDIATYPE,
6082b24ab6bSSebastien Roy 		    DLADM_OPT_ACTIVE);
6092b24ab6bSSebastien Roy 	} else {
6102b24ab6bSSebastien Roy 		(void) i_iptun_down(handle, linkid, &status);
6112b24ab6bSSebastien Roy 	}
6122b24ab6bSSebastien Roy 	return (status);
6132b24ab6bSSebastien Roy }
6142b24ab6bSSebastien Roy 
6152b24ab6bSSebastien Roy dladm_status_t
6162b24ab6bSSebastien Roy dladm_iptun_set6to4relay(dladm_handle_t handle, struct in_addr *relay)
6172b24ab6bSSebastien Roy {
6182b24ab6bSSebastien Roy 	return (i_iptun_ioctl(handle, IPTUN_SET_6TO4RELAY, relay));
6192b24ab6bSSebastien Roy }
6202b24ab6bSSebastien Roy 
6212b24ab6bSSebastien Roy dladm_status_t
6222b24ab6bSSebastien Roy dladm_iptun_get6to4relay(dladm_handle_t handle, struct in_addr *relay)
6232b24ab6bSSebastien Roy {
6242b24ab6bSSebastien Roy 	return (i_iptun_ioctl(handle, IPTUN_GET_6TO4RELAY, relay));
6252b24ab6bSSebastien Roy }
626