6659 nvlist_free(NULL) is a no-op
[illumos-gate.git] / usr / src / lib / libdladm / common / libdliptun.c
blob21c4f5dbd1635bd4337c2fc07225f9e755c03273
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
25 #include <assert.h>
26 #include <stdio.h>
27 #include <errno.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <sys/types.h>
31 #include <fcntl.h>
32 #include <stropts.h>
33 #include <string.h>
34 #include <netdb.h>
35 #include <sys/conf.h>
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <inet/iptun.h>
39 #include <sys/dls.h>
40 #include <libdlpi.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
63 dladm_status_t
64 i_iptun_ioctl(dladm_handle_t handle, int cmd, void *dp)
66 dladm_status_t status = DLADM_STATUS_OK;
67 uint_t attempt;
69 for (attempt = 0; attempt < IPTUN_IOCTL_ATTEMPT_LIMIT; attempt++) {
70 if (attempt != 0)
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)
75 break;
77 return (status);
81 * Given tunnel paramaters as supplied by a library consumer, fill in kernel
82 * parameters to be passed down to the iptun control device.
84 static dladm_status_t
85 i_iptun_kparams(dladm_handle_t handle, const iptun_params_t *params,
86 iptun_kparams_t *ik)
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
107 * IP address.
109 tmpik.iptun_kparam_linkid = params->iptun_param_linkid;
110 status = i_iptun_ioctl(handle, IPTUN_INFO, &tmpik);
111 if (status != DLADM_STATUS_OK)
112 return (status);
113 iptuntype = tmpik.iptun_kparam_type;
116 (void) memset(&hints, 0, sizeof (hints));
117 switch (iptuntype) {
118 case IPTUN_TYPE_IPV4:
119 case IPTUN_TYPE_6TO4:
120 hints.ai_family = AF_INET;
121 break;
122 case IPTUN_TYPE_IPV6:
123 hints.ai_family = AF_INET6;
124 break;
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) {
133 freeaddrinfo(ai);
134 return (DLADM_STATUS_BADIPTUNLADDR);
136 (void) memcpy(&ik->iptun_kparam_laddr, ai->ai_addr,
137 ai->ai_addrlen);
138 ik->iptun_kparam_flags |= IPTUN_KPARAM_LADDR;
139 freeaddrinfo(ai);
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) {
147 freeaddrinfo(ai);
148 return (DLADM_STATUS_BADIPTUNRADDR);
150 (void) memcpy(&ik->iptun_kparam_raddr, ai->ai_addr,
151 ai->ai_addrlen);
152 ik->iptun_kparam_flags |= IPTUN_KPARAM_RADDR;
153 freeaddrinfo(ai);
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)
171 socklen_t salen;
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);
220 dladm_status_t
221 i_iptun_get_sysparams(dladm_handle_t handle, iptun_params_t *params)
223 dladm_status_t status = DLADM_STATUS_OK;
224 iptun_kparams_t ik;
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);
230 return (status);
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;
243 dladm_conf_t conf;
244 datalink_class_t class;
245 uint64_t temp;
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)
250 return (status);
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) {
256 return (status);
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)
263 goto done;
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)) ==
269 DLADM_STATUS_OK)
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)) ==
274 DLADM_STATUS_OK)
275 params->iptun_param_flags |= IPTUN_PARAM_RADDR;
277 done:
278 dladm_destroy_conf(handle, conf);
279 return (status);
282 static dladm_status_t
283 i_iptun_create_sys(dladm_handle_t handle, iptun_params_t *params)
285 iptun_kparams_t ik;
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);
294 return (status);
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)
301 dladm_conf_t conf;
302 dladm_status_t status;
303 uint64_t storage;
305 status = dladm_create_conf(handle, name, params->iptun_param_linkid,
306 DATALINK_CLASS_IPTUN, media, &conf);
307 if (status != DLADM_STATUS_OK)
308 return (status);
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)
315 goto done;
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)
321 goto done;
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)
328 goto done;
331 status = dladm_write_conf(handle, conf);
333 done:
334 dladm_destroy_conf(handle, conf);
335 return (status);
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)
345 return (status);
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)
353 iptun_kparams_t ik;
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);
358 return (status);
361 static dladm_status_t
362 i_iptun_modify_db(dladm_handle_t handle, const iptun_params_t *params)
364 dladm_conf_t conf;
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)
379 return (status);
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)
385 goto done;
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)
392 goto done;
395 status = dladm_write_conf(handle, conf);
397 done:
398 dladm_destroy_conf(handle, conf);
399 return (status);
402 dladm_status_t
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;
408 uint32_t media;
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:
415 media = DL_IPV4;
416 break;
417 case IPTUN_TYPE_IPV6:
418 media = DL_IPV6;
419 break;
420 case IPTUN_TYPE_6TO4:
421 media = DL_6TO4;
422 break;
423 default:
424 return (DLADM_STATUS_IPTUNTYPE);
427 status = dladm_create_datalink_id(handle, name, DATALINK_CLASS_IPTUN,
428 media, linkmgmt_flags, &params->iptun_param_linkid);
429 if (status != DLADM_STATUS_OK)
430 return (status);
432 if (flags & DLADM_OPT_PERSIST) {
433 status = i_iptun_create_db(handle, name, params, media);
434 if (status != DLADM_STATUS_OK)
435 goto done;
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);
446 done:
447 if (status != DLADM_STATUS_OK) {
448 (void) dladm_destroy_datalink_id(handle,
449 params->iptun_param_linkid, flags);
451 return (status);
454 dladm_status_t
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)
463 return (status);
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
473 * persistently.
475 status = i_iptun_delete_sys(handle, linkid);
476 if (status != DLADM_STATUS_OK &&
477 (status != DLADM_STATUS_NOTFOUND ||
478 !(flags & DLADM_OPT_PERSIST)))
479 return (status);
482 if (flags & DLADM_OPT_PERSIST) {
483 (void) dladm_remove_conf(handle, linkid);
484 (void) dladm_destroy_datalink_id(handle, linkid,
485 DLADM_OPT_PERSIST);
487 return (DLADM_STATUS_OK);
490 dladm_status_t
491 dladm_iptun_modify(dladm_handle_t handle, const iptun_params_t *params,
492 uint32_t flags)
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
499 * policy.
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)
513 return (status);
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)
519 return (status);
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);
529 return (status);
532 dladm_status_t
533 dladm_iptun_getparams(dladm_handle_t handle, iptun_params_t *params,
534 uint32_t flags)
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));
540 else
541 return (DLADM_STATUS_BADARG);
544 static int
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)
554 goto done;
555 id_up = B_TRUE;
557 (void) memset(&params, 0, sizeof (params));
559 params.iptun_param_linkid = linkid;
560 if ((status = i_iptun_get_dbparams(handle, &params)) == DLADM_STATUS_OK)
561 status = i_iptun_create_sys(handle, &params);
562 done:
563 if (statusp != NULL)
564 *statusp = status;
565 if (status != DLADM_STATUS_OK && id_up) {
566 (void) dladm_destroy_datalink_id(handle, linkid,
567 DLADM_OPT_ACTIVE);
569 return (DLADM_WALK_CONTINUE);
572 static int
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);
579 if (statusp != NULL)
580 *statusp = status;
581 return (DLADM_WALK_CONTINUE);
584 /* ARGSUSED */
585 dladm_status_t
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,
593 DLADM_OPT_PERSIST);
594 } else {
595 (void) i_iptun_up(handle, linkid, &status);
597 return (status);
600 dladm_status_t
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,
608 DLADM_OPT_ACTIVE);
609 } else {
610 (void) i_iptun_down(handle, linkid, &status);
612 return (status);
615 dladm_status_t
616 dladm_iptun_set6to4relay(dladm_handle_t handle, struct in_addr *relay)
618 return (i_iptun_ioctl(handle, IPTUN_SET_6TO4RELAY, relay));
621 dladm_status_t
622 dladm_iptun_get6to4relay(dladm_handle_t handle, struct in_addr *relay)
624 return (i_iptun_ioctl(handle, IPTUN_GET_6TO4RELAY, relay));