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]
22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
30 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <inet/iptun.h>
41 #include <libdladm_impl.h>
42 #include <libdllink.h>
43 #include <libdliptun.h>
46 * IP Tunneling Administration Library.
47 * This library is used by dladm(1M) and to configure IP tunnel links.
50 #define IPTUN_CONF_TYPE "type"
51 #define IPTUN_CONF_LADDR "laddr"
52 #define IPTUN_CONF_RADDR "raddr"
55 * If IPTUN_CREATE and IPTUN_MODIFY include IPsec policy and IPsec hasn't
56 * loaded yet, the ioctls may return EAGAIN. We try the ioctl
57 * IPTUN_IOCTL_ATTEMPT_LIMIT times and wait IPTUN_IOCTL_ATTEMPT_INTERVAL
58 * microseconds between attempts.
60 #define IPTUN_IOCTL_ATTEMPT_LIMIT 3
61 #define IPTUN_IOCTL_ATTEMPT_INTERVAL 10000
64 i_iptun_ioctl(dladm_handle_t handle
, int cmd
, void *dp
)
66 dladm_status_t status
= DLADM_STATUS_OK
;
69 for (attempt
= 0; attempt
< IPTUN_IOCTL_ATTEMPT_LIMIT
; attempt
++) {
71 (void) usleep(IPTUN_IOCTL_ATTEMPT_INTERVAL
);
72 status
= (ioctl(dladm_dld_fd(handle
), cmd
, dp
) == 0) ?
73 DLADM_STATUS_OK
: dladm_errno2status(errno
);
74 if (status
!= DLADM_STATUS_TRYAGAIN
)
81 * Given tunnel paramaters as supplied by a library consumer, fill in kernel
82 * parameters to be passed down to the iptun control device.
85 i_iptun_kparams(dladm_handle_t handle
, const iptun_params_t
*params
,
88 dladm_status_t status
;
89 struct addrinfo
*ai
, hints
;
90 iptun_kparams_t tmpik
;
91 iptun_type_t iptuntype
= IPTUN_TYPE_UNKNOWN
;
93 (void) memset(ik
, 0, sizeof (*ik
));
95 ik
->iptun_kparam_linkid
= params
->iptun_param_linkid
;
97 if (params
->iptun_param_flags
& IPTUN_PARAM_TYPE
) {
98 ik
->iptun_kparam_type
= iptuntype
= params
->iptun_param_type
;
99 ik
->iptun_kparam_flags
|= IPTUN_KPARAM_TYPE
;
102 if (params
->iptun_param_flags
& (IPTUN_PARAM_LADDR
|IPTUN_PARAM_RADDR
)) {
103 if (iptuntype
== IPTUN_TYPE_UNKNOWN
) {
105 * We need to get the type of this existing tunnel in
106 * order to validate and/or look up the right kind of
109 tmpik
.iptun_kparam_linkid
= params
->iptun_param_linkid
;
110 status
= i_iptun_ioctl(handle
, IPTUN_INFO
, &tmpik
);
111 if (status
!= DLADM_STATUS_OK
)
113 iptuntype
= tmpik
.iptun_kparam_type
;
116 (void) memset(&hints
, 0, sizeof (hints
));
118 case IPTUN_TYPE_IPV4
:
119 case IPTUN_TYPE_6TO4
:
120 hints
.ai_family
= AF_INET
;
122 case IPTUN_TYPE_IPV6
:
123 hints
.ai_family
= AF_INET6
;
128 if (params
->iptun_param_flags
& IPTUN_PARAM_LADDR
) {
129 if (getaddrinfo(params
->iptun_param_laddr
, NULL
, &hints
, &ai
) !=
131 return (DLADM_STATUS_BADIPTUNLADDR
);
132 if (ai
->ai_next
!= NULL
) {
134 return (DLADM_STATUS_BADIPTUNLADDR
);
136 (void) memcpy(&ik
->iptun_kparam_laddr
, ai
->ai_addr
,
138 ik
->iptun_kparam_flags
|= IPTUN_KPARAM_LADDR
;
142 if (params
->iptun_param_flags
& IPTUN_PARAM_RADDR
) {
143 if (getaddrinfo(params
->iptun_param_raddr
, NULL
, &hints
, &ai
) !=
145 return (DLADM_STATUS_BADIPTUNRADDR
);
146 if (ai
->ai_next
!= NULL
) {
148 return (DLADM_STATUS_BADIPTUNRADDR
);
150 (void) memcpy(&ik
->iptun_kparam_raddr
, ai
->ai_addr
,
152 ik
->iptun_kparam_flags
|= IPTUN_KPARAM_RADDR
;
156 if (params
->iptun_param_flags
& IPTUN_PARAM_SECINFO
) {
157 ik
->iptun_kparam_secinfo
= params
->iptun_param_secinfo
;
158 ik
->iptun_kparam_flags
|= IPTUN_KPARAM_SECINFO
;
161 return (DLADM_STATUS_OK
);
165 * The inverse of i_iptun_kparams(). Given kernel tunnel paramaters as
166 * returned from an IPTUN_INFO ioctl, fill in tunnel parameters.
168 static dladm_status_t
169 i_iptun_params(const iptun_kparams_t
*ik
, iptun_params_t
*params
)
173 (void) memset(params
, 0, sizeof (*params
));
175 params
->iptun_param_linkid
= ik
->iptun_kparam_linkid
;
177 if (ik
->iptun_kparam_flags
& IPTUN_KPARAM_TYPE
) {
178 params
->iptun_param_type
= ik
->iptun_kparam_type
;
179 params
->iptun_param_flags
|= IPTUN_PARAM_TYPE
;
182 if (ik
->iptun_kparam_flags
& IPTUN_KPARAM_LADDR
) {
183 salen
= ik
->iptun_kparam_laddr
.ss_family
== AF_INET
?
184 sizeof (struct sockaddr_in
) : sizeof (struct sockaddr_in6
);
185 if (getnameinfo((const struct sockaddr
*)
186 &ik
->iptun_kparam_laddr
, salen
, params
->iptun_param_laddr
,
187 sizeof (params
->iptun_param_laddr
), NULL
, 0,
188 NI_NUMERICHOST
) != 0) {
189 return (DLADM_STATUS_BADIPTUNLADDR
);
191 params
->iptun_param_flags
|= IPTUN_PARAM_LADDR
;
194 if (ik
->iptun_kparam_flags
& IPTUN_KPARAM_RADDR
) {
195 salen
= ik
->iptun_kparam_raddr
.ss_family
== AF_INET
?
196 sizeof (struct sockaddr_in
) : sizeof (struct sockaddr_in6
);
197 if (getnameinfo((const struct sockaddr
*)
198 &ik
->iptun_kparam_raddr
, salen
, params
->iptun_param_raddr
,
199 sizeof (params
->iptun_param_raddr
), NULL
, 0,
200 NI_NUMERICHOST
) != 0) {
201 return (DLADM_STATUS_BADIPTUNRADDR
);
203 params
->iptun_param_flags
|= IPTUN_PARAM_RADDR
;
206 if (ik
->iptun_kparam_flags
& IPTUN_KPARAM_SECINFO
) {
207 params
->iptun_param_secinfo
= ik
->iptun_kparam_secinfo
;
208 params
->iptun_param_flags
|= IPTUN_PARAM_SECINFO
;
211 if (ik
->iptun_kparam_flags
& IPTUN_KPARAM_IMPLICIT
)
212 params
->iptun_param_flags
|= IPTUN_PARAM_IMPLICIT
;
214 if (ik
->iptun_kparam_flags
& IPTUN_KPARAM_IPSECPOL
)
215 params
->iptun_param_flags
|= IPTUN_PARAM_IPSECPOL
;
217 return (DLADM_STATUS_OK
);
221 i_iptun_get_sysparams(dladm_handle_t handle
, iptun_params_t
*params
)
223 dladm_status_t status
= DLADM_STATUS_OK
;
226 ik
.iptun_kparam_linkid
= params
->iptun_param_linkid
;
227 status
= i_iptun_ioctl(handle
, IPTUN_INFO
, &ik
);
228 if (status
== DLADM_STATUS_OK
)
229 status
= i_iptun_params(&ik
, params
);
234 * Read tunnel parameters from persistent storage. Note that the tunnel type
235 * is the only thing which must always be in the configuratioh. All other
236 * parameters (currently the source and destination addresses) may or may not
237 * have been configured, and therefore may not have been set.
239 static dladm_status_t
240 i_iptun_get_dbparams(dladm_handle_t handle
, iptun_params_t
*params
)
242 dladm_status_t status
;
244 datalink_class_t
class;
247 /* First, make sure that this is an IP tunnel. */
248 if ((status
= dladm_datalink_id2info(handle
, params
->iptun_param_linkid
,
249 NULL
, &class, NULL
, NULL
, 0)) != DLADM_STATUS_OK
)
251 if (class != DATALINK_CLASS_IPTUN
)
252 return (DLADM_STATUS_LINKINVAL
);
254 if ((status
= dladm_getsnap_conf(handle
, params
->iptun_param_linkid
,
255 &conf
)) != DLADM_STATUS_OK
) {
259 params
->iptun_param_flags
= 0;
261 if ((status
= dladm_get_conf_field(handle
, conf
, IPTUN_CONF_TYPE
, &temp
,
262 sizeof (temp
))) != DLADM_STATUS_OK
)
264 params
->iptun_param_type
= (iptun_type_t
)temp
;
265 params
->iptun_param_flags
|= IPTUN_PARAM_TYPE
;
267 if (dladm_get_conf_field(handle
, conf
, IPTUN_CONF_LADDR
,
268 params
->iptun_param_laddr
, sizeof (params
->iptun_param_laddr
)) ==
270 params
->iptun_param_flags
|= IPTUN_PARAM_LADDR
;
272 if (dladm_get_conf_field(handle
, conf
, IPTUN_CONF_RADDR
,
273 params
->iptun_param_raddr
, sizeof (params
->iptun_param_raddr
)) ==
275 params
->iptun_param_flags
|= IPTUN_PARAM_RADDR
;
278 dladm_destroy_conf(handle
, conf
);
282 static dladm_status_t
283 i_iptun_create_sys(dladm_handle_t handle
, iptun_params_t
*params
)
286 dladm_status_t status
= DLADM_STATUS_OK
;
288 /* The tunnel type is required for creation. */
289 if (!(params
->iptun_param_flags
& IPTUN_PARAM_TYPE
))
290 return (DLADM_STATUS_IPTUNTYPEREQD
);
292 if ((status
= i_iptun_kparams(handle
, params
, &ik
)) == DLADM_STATUS_OK
)
293 status
= i_iptun_ioctl(handle
, IPTUN_CREATE
, &ik
);
297 static dladm_status_t
298 i_iptun_create_db(dladm_handle_t handle
, const char *name
,
299 iptun_params_t
*params
, uint32_t media
)
302 dladm_status_t status
;
305 status
= dladm_create_conf(handle
, name
, params
->iptun_param_linkid
,
306 DATALINK_CLASS_IPTUN
, media
, &conf
);
307 if (status
!= DLADM_STATUS_OK
)
310 assert(params
->iptun_param_flags
& IPTUN_PARAM_TYPE
);
311 storage
= params
->iptun_param_type
;
312 status
= dladm_set_conf_field(handle
, conf
, IPTUN_CONF_TYPE
,
313 DLADM_TYPE_UINT64
, &storage
);
314 if (status
!= DLADM_STATUS_OK
)
317 if (params
->iptun_param_flags
& IPTUN_PARAM_LADDR
) {
318 status
= dladm_set_conf_field(handle
, conf
, IPTUN_CONF_LADDR
,
319 DLADM_TYPE_STR
, params
->iptun_param_laddr
);
320 if (status
!= DLADM_STATUS_OK
)
324 if (params
->iptun_param_flags
& IPTUN_PARAM_RADDR
) {
325 status
= dladm_set_conf_field(handle
, conf
, IPTUN_CONF_RADDR
,
326 DLADM_TYPE_STR
, params
->iptun_param_raddr
);
327 if (status
!= DLADM_STATUS_OK
)
331 status
= dladm_write_conf(handle
, conf
);
334 dladm_destroy_conf(handle
, conf
);
338 static dladm_status_t
339 i_iptun_delete_sys(dladm_handle_t handle
, datalink_id_t linkid
)
341 dladm_status_t status
;
343 status
= i_iptun_ioctl(handle
, IPTUN_DELETE
, &linkid
);
344 if (status
!= DLADM_STATUS_OK
)
346 (void) dladm_destroy_datalink_id(handle
, linkid
, DLADM_OPT_ACTIVE
);
347 return (DLADM_STATUS_OK
);
350 static dladm_status_t
351 i_iptun_modify_sys(dladm_handle_t handle
, const iptun_params_t
*params
)
354 dladm_status_t status
;
356 if ((status
= i_iptun_kparams(handle
, params
, &ik
)) == DLADM_STATUS_OK
)
357 status
= i_iptun_ioctl(handle
, IPTUN_MODIFY
, &ik
);
361 static dladm_status_t
362 i_iptun_modify_db(dladm_handle_t handle
, const iptun_params_t
*params
)
365 dladm_status_t status
;
367 assert(params
->iptun_param_flags
&
368 (IPTUN_PARAM_LADDR
|IPTUN_PARAM_RADDR
));
371 * The only parameters that can be modified persistently are the local
372 * and remote addresses.
374 if (params
->iptun_param_flags
& ~(IPTUN_PARAM_LADDR
|IPTUN_PARAM_RADDR
))
375 return (DLADM_STATUS_BADARG
);
377 status
= dladm_open_conf(handle
, params
->iptun_param_linkid
, &conf
);
378 if (status
!= DLADM_STATUS_OK
)
381 if (params
->iptun_param_flags
& IPTUN_PARAM_LADDR
) {
382 status
= dladm_set_conf_field(handle
, conf
, IPTUN_CONF_LADDR
,
383 DLADM_TYPE_STR
, (void *)params
->iptun_param_laddr
);
384 if (status
!= DLADM_STATUS_OK
)
388 if (params
->iptun_param_flags
& IPTUN_PARAM_RADDR
) {
389 status
= dladm_set_conf_field(handle
, conf
, IPTUN_CONF_RADDR
,
390 DLADM_TYPE_STR
, (void *)params
->iptun_param_raddr
);
391 if (status
!= DLADM_STATUS_OK
)
395 status
= dladm_write_conf(handle
, conf
);
398 dladm_destroy_conf(handle
, conf
);
403 dladm_iptun_create(dladm_handle_t handle
, const char *name
,
404 iptun_params_t
*params
, uint32_t flags
)
406 dladm_status_t status
;
407 uint32_t linkmgmt_flags
= flags
;
410 if (!(params
->iptun_param_flags
& IPTUN_PARAM_TYPE
))
411 return (DLADM_STATUS_IPTUNTYPEREQD
);
413 switch (params
->iptun_param_type
) {
414 case IPTUN_TYPE_IPV4
:
417 case IPTUN_TYPE_IPV6
:
420 case IPTUN_TYPE_6TO4
:
424 return (DLADM_STATUS_IPTUNTYPE
);
427 status
= dladm_create_datalink_id(handle
, name
, DATALINK_CLASS_IPTUN
,
428 media
, linkmgmt_flags
, ¶ms
->iptun_param_linkid
);
429 if (status
!= DLADM_STATUS_OK
)
432 if (flags
& DLADM_OPT_PERSIST
) {
433 status
= i_iptun_create_db(handle
, name
, params
, media
);
434 if (status
!= DLADM_STATUS_OK
)
438 if (flags
& DLADM_OPT_ACTIVE
) {
439 status
= i_iptun_create_sys(handle
, params
);
440 if (status
!= DLADM_STATUS_OK
&& (flags
& DLADM_OPT_PERSIST
)) {
441 (void) dladm_remove_conf(handle
,
442 params
->iptun_param_linkid
);
447 if (status
!= DLADM_STATUS_OK
) {
448 (void) dladm_destroy_datalink_id(handle
,
449 params
->iptun_param_linkid
, flags
);
455 dladm_iptun_delete(dladm_handle_t handle
, datalink_id_t linkid
, uint32_t flags
)
457 dladm_status_t status
;
458 datalink_class_t
class;
460 /* First, make sure that this is an IP tunnel. */
461 if ((status
= dladm_datalink_id2info(handle
, linkid
, NULL
, &class, NULL
,
462 NULL
, 0)) != DLADM_STATUS_OK
)
464 if (class != DATALINK_CLASS_IPTUN
)
465 return (DLADM_STATUS_LINKINVAL
);
467 if (flags
& DLADM_OPT_ACTIVE
) {
469 * Note that if i_iptun_delete_sys() fails with
470 * DLADM_STATUS_NOTFOUND and the caller also wishes to delete
471 * the persistent configuration, we still fall through to the
472 * DLADM_OPT_PERSIST case in case the tunnel only exists
475 status
= i_iptun_delete_sys(handle
, linkid
);
476 if (status
!= DLADM_STATUS_OK
&&
477 (status
!= DLADM_STATUS_NOTFOUND
||
478 !(flags
& DLADM_OPT_PERSIST
)))
482 if (flags
& DLADM_OPT_PERSIST
) {
483 (void) dladm_remove_conf(handle
, linkid
);
484 (void) dladm_destroy_datalink_id(handle
, linkid
,
487 return (DLADM_STATUS_OK
);
491 dladm_iptun_modify(dladm_handle_t handle
, const iptun_params_t
*params
,
494 dladm_status_t status
= DLADM_STATUS_OK
;
495 iptun_params_t old_params
;
498 * We can only modify the tunnel source, tunnel destination, or IPsec
501 if (!(params
->iptun_param_flags
&
502 (IPTUN_PARAM_LADDR
|IPTUN_PARAM_RADDR
|IPTUN_PARAM_SECINFO
)))
503 return (DLADM_STATUS_BADARG
);
505 if (flags
& DLADM_OPT_PERSIST
) {
507 * Before we change the database, save the old configuration
508 * so that we can revert back if an error occurs.
510 old_params
.iptun_param_linkid
= params
->iptun_param_linkid
;
511 status
= i_iptun_get_dbparams(handle
, &old_params
);
512 if (status
!= DLADM_STATUS_OK
)
514 /* we'll only need to revert the parameters being modified */
515 old_params
.iptun_param_flags
= params
->iptun_param_flags
;
517 status
= i_iptun_modify_db(handle
, params
);
518 if (status
!= DLADM_STATUS_OK
)
522 if (flags
& DLADM_OPT_ACTIVE
) {
523 status
= i_iptun_modify_sys(handle
, params
);
524 if (status
!= DLADM_STATUS_OK
&& (flags
& DLADM_OPT_PERSIST
)) {
525 (void) i_iptun_modify_db(handle
, &old_params
);
533 dladm_iptun_getparams(dladm_handle_t handle
, iptun_params_t
*params
,
536 if (flags
== DLADM_OPT_ACTIVE
)
537 return (i_iptun_get_sysparams(handle
, params
));
538 else if (flags
== DLADM_OPT_PERSIST
)
539 return (i_iptun_get_dbparams(handle
, params
));
541 return (DLADM_STATUS_BADARG
);
545 i_iptun_up(dladm_handle_t handle
, datalink_id_t linkid
, void *arg
)
547 dladm_status_t
*statusp
= arg
;
548 dladm_status_t status
;
549 iptun_params_t params
;
550 boolean_t id_up
= B_FALSE
;
552 status
= dladm_up_datalink_id(handle
, linkid
);
553 if (status
!= DLADM_STATUS_OK
)
557 (void) memset(¶ms
, 0, sizeof (params
));
559 params
.iptun_param_linkid
= linkid
;
560 if ((status
= i_iptun_get_dbparams(handle
, ¶ms
)) == DLADM_STATUS_OK
)
561 status
= i_iptun_create_sys(handle
, ¶ms
);
565 if (status
!= DLADM_STATUS_OK
&& id_up
) {
566 (void) dladm_destroy_datalink_id(handle
, linkid
,
569 return (DLADM_WALK_CONTINUE
);
573 i_iptun_down(dladm_handle_t handle
, datalink_id_t linkid
, void *arg
)
575 dladm_status_t
*statusp
= arg
;
576 dladm_status_t status
;
578 status
= i_iptun_delete_sys(handle
, linkid
);
581 return (DLADM_WALK_CONTINUE
);
586 dladm_iptun_up(dladm_handle_t handle
, datalink_id_t linkid
)
588 dladm_status_t status
= DLADM_STATUS_OK
;
590 if (linkid
== DATALINK_ALL_LINKID
) {
591 (void) dladm_walk_datalink_id(i_iptun_up
, handle
, NULL
,
592 DATALINK_CLASS_IPTUN
, DATALINK_ANY_MEDIATYPE
,
595 (void) i_iptun_up(handle
, linkid
, &status
);
601 dladm_iptun_down(dladm_handle_t handle
, datalink_id_t linkid
)
603 dladm_status_t status
= DLADM_STATUS_OK
;
605 if (linkid
== DATALINK_ALL_LINKID
) {
606 (void) dladm_walk_datalink_id(i_iptun_down
, handle
, NULL
,
607 DATALINK_CLASS_IPTUN
, DATALINK_ANY_MEDIATYPE
,
610 (void) i_iptun_down(handle
, linkid
, &status
);
616 dladm_iptun_set6to4relay(dladm_handle_t handle
, struct in_addr
*relay
)
618 return (i_iptun_ioctl(handle
, IPTUN_SET_6TO4RELAY
, relay
));
622 dladm_iptun_get6to4relay(dladm_handle_t handle
, struct in_addr
*relay
)
624 return (i_iptun_ioctl(handle
, IPTUN_GET_6TO4RELAY
, relay
));