3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <stropts.h>
32 #include <sys/sockio.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <sys/socket.h>
36 #include <net/route.h>
37 #include <netinet/in.h>
38 #include <inet/ip.h>
39 #include <arpa/inet.h>
40 #include <libintl.h>
41 #include <libdlpi.h>
42 #include <libinetutil.h>
508
509 if (iph->iph_dlh == NULL) {
510 assert(iph->iph_zoneid != GLOBAL_ZONEID);
511 return (B_FALSE);
512 }
513 dlstatus = dladm_name2info(iph->iph_dlh, ifname, &linkid, NULL,
514 &class, NULL);
515 if (dlstatus == DLADM_STATUS_OK && class == DATALINK_CLASS_IPTUN) {
516 params.iptun_param_linkid = linkid;
517 dlstatus = dladm_iptun_getparams(iph->iph_dlh, ¶ms,
518 DLADM_OPT_ACTIVE);
519 if (dlstatus == DLADM_STATUS_OK &&
520 params.iptun_param_type == IPTUN_TYPE_6TO4) {
521 return (B_TRUE);
522 }
523 }
524 return (B_FALSE);
525 }
526
527 /*
528 * Returns B_TRUE if `ifname' represents an IPMP underlying interface.
529 */
530 boolean_t
531 i_ipadm_is_under_ipmp(ipadm_handle_t iph, const char *ifname)
532 {
533 struct lifreq lifr;
534
535 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
536 if (ioctl(iph->iph_sock, SIOCGLIFGROUPNAME, (caddr_t)&lifr) < 0) {
537 if (ioctl(iph->iph_sock6, SIOCGLIFGROUPNAME,
538 (caddr_t)&lifr) < 0) {
539 return (B_FALSE);
540 }
541 }
542 return (lifr.lifr_groupname[0] != '\0');
543 }
544
545 /*
546 * Returns B_TRUE if `ifname' represents an IPMP meta-interface.
547 */
548 boolean_t
549 i_ipadm_is_ipmp(ipadm_handle_t iph, const char *ifname)
550 {
551 uint64_t flags;
552
553 if (i_ipadm_get_flags(iph, ifname, AF_INET, &flags) != IPADM_SUCCESS &&
554 i_ipadm_get_flags(iph, ifname, AF_INET6, &flags) != IPADM_SUCCESS)
555 return (B_FALSE);
556
557 return ((flags & IFF_IPMP) != 0);
558 }
559
560 /*
561 * For a given interface name, ipadm_if_enabled() checks if v4
562 * or v6 or both IP interfaces exist in the active configuration.
563 */
564 boolean_t
565 ipadm_if_enabled(ipadm_handle_t iph, const char *ifname, sa_family_t af)
566 {
567 struct lifreq lifr;
568 int s4 = iph->iph_sock;
569 int s6 = iph->iph_sock6;
570
571 bzero(&lifr, sizeof (lifr));
572 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
573 switch (af) {
574 case AF_INET:
575 if (ioctl(s4, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0)
576 return (B_TRUE);
577 break;
578 case AF_INET6:
579 if (ioctl(s6, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0)
580 return (B_TRUE);
673 case IPADM_ADDR_NONE:
674 status = ipadm_set_addrprop(iph, name, pval, aobjname,
675 IPADM_OPT_ACTIVE);
676 break;
677 }
678
679 return (status);
680 }
681
682 /*
683 * Instantiate the interface object by retrieving the configuration from
684 * `ifnvl'. The nvlist `ifnvl' contains all the persistent configuration
685 * (interface properties and address objects on that interface) for the
686 * given `ifname'.
687 */
688 ipadm_status_t
689 i_ipadm_init_ifobj(ipadm_handle_t iph, const char *ifname, nvlist_t *ifnvl)
690 {
691 nvlist_t *nvl = NULL;
692 nvpair_t *nvp;
693 char *afstr;
694 ipadm_status_t status;
695 ipadm_status_t ret_status = IPADM_SUCCESS;
696 char newifname[LIFNAMSIZ];
697 char *aobjstr;
698 sa_family_t af = AF_UNSPEC;
699 boolean_t is_ngz = (iph->iph_zoneid != GLOBAL_ZONEID);
700
701 (void) strlcpy(newifname, ifname, sizeof (newifname));
702 /*
703 * First plumb the given interface and then apply all the persistent
704 * interface properties and then instantiate any persistent addresses
705 * objects on that interface.
706 */
707 for (nvp = nvlist_next_nvpair(ifnvl, NULL); nvp != NULL;
708 nvp = nvlist_next_nvpair(ifnvl, nvp)) {
709 if (nvpair_value_nvlist(nvp, &nvl) != 0)
710 continue;
711
712 if (nvlist_lookup_string(nvl, IPADM_NVP_FAMILY, &afstr) == 0) {
713 status = i_ipadm_plumb_if(iph, newifname, atoi(afstr),
714 IPADM_OPT_ACTIVE);
715 /*
716 * If the interface is already plumbed, we should
717 * ignore this error because there might be address
718 * address objects on that interface that needs to
719 * be enabled again.
720 */
721 if (status == IPADM_IF_EXISTS)
722 status = IPADM_SUCCESS;
723
724 if (is_ngz)
725 af = atoi(afstr);
726 } else if (nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME,
727 &aobjstr) == 0) {
728 /*
729 * For a static address, we need to search for
730 * the prefixlen in the nvlist `ifnvl'.
731 */
732 if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) ||
733 nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) {
734 status = i_ipadm_merge_prefixlen_from_nvl(ifnvl,
735 nvl, aobjstr);
736 if (status != IPADM_SUCCESS)
737 continue;
738 }
739 status = i_ipadm_init_addrobj(iph, nvl);
740 /*
741 * If this address is in use on some other interface,
742 * we want to record an error to be returned as
743 * a soft error and continue processing the rest of
744 * the addresses.
745 */
746 if (status == IPADM_ADDR_NOTAVAIL) {
747 ret_status = IPADM_ALL_ADDRS_NOT_ENABLED;
748 status = IPADM_SUCCESS;
749 }
750 } else {
751 assert(nvlist_exists(nvl, IPADM_NVP_PROTONAME));
752 status = i_ipadm_init_ifprop(iph, nvl);
753 }
754 if (status != IPADM_SUCCESS)
755 return (status);
756 }
757
758 if (is_ngz && af != AF_UNSPEC)
759 ret_status = ipadm_init_net_from_gz(iph, newifname, NULL);
760 return (ret_status);
761 }
762
763 /*
764 * Retrieves the persistent configuration for the given interface(s) in `ifs'
765 * by contacting the daemon and dumps the information in `allifs'.
766 */
767 ipadm_status_t
768 i_ipadm_init_ifs(ipadm_handle_t iph, const char *ifs, nvlist_t **allifs)
769 {
770 nvlist_t *nvl = NULL;
771 size_t nvlsize, bufsize;
772 ipmgmt_initif_arg_t *iargp;
773 char *buf = NULL, *nvlbuf = NULL;
774 ipmgmt_get_rval_t *rvalp = NULL;
775 int err;
776 ipadm_status_t status = IPADM_SUCCESS;
777
778 if ((err = ipadm_str2nvlist(ifs, &nvl, IPADM_NORVAL)) != 0)
779 return (ipadm_errno2status(err));
936 * to new buffer.
937 */
938 if (err == 0) {
939 void *newp;
940
941 /* allocated memory will be freed by the caller */
942 if ((newp = realloc(*rbufp, darg.rsize)) == NULL) {
943 err = ENOMEM;
944 } else {
945 *rbufp = newp;
946 (void) memcpy(*rbufp, darg.rbuf, darg.rsize);
947 }
948 }
949 /* munmap() the door buffer */
950 (void) munmap(darg.rbuf, darg.rsize);
951 } else {
952 if (darg.rsize != rsize)
953 err = EBADE;
954 }
955 return (err);
956 }
|
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
24 */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <stropts.h>
33 #include <sys/sockio.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <sys/socket.h>
37 #include <net/route.h>
38 #include <netinet/in.h>
39 #include <inet/ip.h>
40 #include <arpa/inet.h>
41 #include <libintl.h>
42 #include <libdlpi.h>
43 #include <libinetutil.h>
509
510 if (iph->iph_dlh == NULL) {
511 assert(iph->iph_zoneid != GLOBAL_ZONEID);
512 return (B_FALSE);
513 }
514 dlstatus = dladm_name2info(iph->iph_dlh, ifname, &linkid, NULL,
515 &class, NULL);
516 if (dlstatus == DLADM_STATUS_OK && class == DATALINK_CLASS_IPTUN) {
517 params.iptun_param_linkid = linkid;
518 dlstatus = dladm_iptun_getparams(iph->iph_dlh, ¶ms,
519 DLADM_OPT_ACTIVE);
520 if (dlstatus == DLADM_STATUS_OK &&
521 params.iptun_param_type == IPTUN_TYPE_6TO4) {
522 return (B_TRUE);
523 }
524 }
525 return (B_FALSE);
526 }
527
528 /*
529 * For a given interface name, ipadm_if_enabled() checks if v4
530 * or v6 or both IP interfaces exist in the active configuration.
531 */
532 boolean_t
533 ipadm_if_enabled(ipadm_handle_t iph, const char *ifname, sa_family_t af)
534 {
535 struct lifreq lifr;
536 int s4 = iph->iph_sock;
537 int s6 = iph->iph_sock6;
538
539 bzero(&lifr, sizeof (lifr));
540 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
541 switch (af) {
542 case AF_INET:
543 if (ioctl(s4, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0)
544 return (B_TRUE);
545 break;
546 case AF_INET6:
547 if (ioctl(s6, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0)
548 return (B_TRUE);
641 case IPADM_ADDR_NONE:
642 status = ipadm_set_addrprop(iph, name, pval, aobjname,
643 IPADM_OPT_ACTIVE);
644 break;
645 }
646
647 return (status);
648 }
649
650 /*
651 * Instantiate the interface object by retrieving the configuration from
652 * `ifnvl'. The nvlist `ifnvl' contains all the persistent configuration
653 * (interface properties and address objects on that interface) for the
654 * given `ifname'.
655 */
656 ipadm_status_t
657 i_ipadm_init_ifobj(ipadm_handle_t iph, const char *ifname, nvlist_t *ifnvl)
658 {
659 nvlist_t *nvl = NULL;
660 nvpair_t *nvp;
661 ipadm_status_t status;
662 ipadm_status_t ret_status = IPADM_SUCCESS;
663 char newifname[LIFNAMSIZ];
664 char *aobjstr;
665 char *ifclass_str, *gif_name;
666 uint16_t *families;
667 uint_t nelem = 0;
668 char **members;
669 uint32_t ipadm_flags;
670 boolean_t is_ngz = (iph->iph_zoneid != GLOBAL_ZONEID);
671 boolean_t init_from_gz = B_FALSE;
672
673 (void) strlcpy(newifname, ifname, sizeof (newifname));
674 /*
675 * First plumb the given interface and then apply all the persistent
676 * interface properties and then instantiate any persistent addresses
677 * objects on that interface.
678 */
679 for (nvp = nvlist_next_nvpair(ifnvl, NULL); nvp != NULL;
680 nvp = nvlist_next_nvpair(ifnvl, nvp)) {
681
682 if (nvpair_value_nvlist(nvp, &nvl) != 0)
683 continue;
684
685
686 if (nvlist_lookup_uint16_array(nvl, IPADM_NVP_FAMILIES,
687 &families, &nelem) == 0) {
688
689 ipadm_flags = IPADM_OPT_ACTIVE;
690
691 if (nvlist_lookup_string(nvl, IPADM_NVP_IFCLASS, &ifclass_str) == 0 &&
692 atoi(ifclass_str) == IPADM_IF_CLASS_IPMP)
693 ipadm_flags |= IPADM_OPT_IPMP;
694
695 while (nelem--) {
696 assert(families[nelem] == AF_INET ||
697 families[nelem] == AF_INET6);
698
699 status = i_ipadm_plumb_if(iph, newifname, families[nelem],
700 ipadm_flags);
701
702 if (status == IPADM_IF_EXISTS)
703 status = IPADM_SUCCESS;
704
705 /* plumbing can fail for ipmp, this is expected */
706 if (status != IPADM_SUCCESS && !(ipadm_flags & IPADM_OPT_IPMP))
707 break;
708 }
709 /* does this interface belong to ipmp ? */
710 if (nvlist_lookup_string(nvl, IPADM_NVP_GIFNAME, &gif_name) == 0) {
711 (void) ipadm_create_if(iph, gif_name, AF_INET, IPADM_OPT_IPMP |
712 IPADM_OPT_ACTIVE);
713 (void) ipadm_create_if(iph, gif_name, AF_INET6, IPADM_OPT_IPMP |
714 IPADM_OPT_ACTIVE);
715 /** add itself to the group */
716 status = ipadm_add_ipmp_member(iph, gif_name, newifname, IPADM_OPT_ACTIVE);
717 if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS)
718 break;
719 }
720 if (is_ngz)
721 init_from_gz = B_TRUE;
722 } else if (nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME,
723 &aobjstr) == 0) {
724 /*
725 * For a static address, we need to search for
726 * the prefixlen in the nvlist `ifnvl'.
727 */
728 if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) ||
729 nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) {
730 status = i_ipadm_merge_prefixlen_from_nvl(ifnvl,
731 nvl, aobjstr);
732
733 if (status != IPADM_SUCCESS)
734 continue;
735 }
736 status = i_ipadm_init_addrobj(iph, nvl);
737 /*
738 * If this address is in use on some other interface,
739 * we want to record an error to be returned as
740 * a soft error and continue processing the rest of
741 * the addresses.
742 */
743 if (status == IPADM_ADDR_NOTAVAIL) {
744 ret_status = IPADM_ALL_ADDRS_NOT_ENABLED;
745 status = IPADM_SUCCESS;
746 }
747 } else {
748 assert(nvlist_exists(nvl, IPADM_NVP_PROTONAME));
749 status = i_ipadm_init_ifprop(iph, nvl);
750 }
751 if (status != IPADM_SUCCESS)
752 return (status);
753 }
754 if (init_from_gz)
755 ret_status = ipadm_init_net_from_gz(iph, newifname, NULL);
756
757 return (ret_status);
758 }
759
760 /*
761 * Retrieves the persistent configuration for the given interface(s) in `ifs'
762 * by contacting the daemon and dumps the information in `allifs'.
763 */
764 ipadm_status_t
765 i_ipadm_init_ifs(ipadm_handle_t iph, const char *ifs, nvlist_t **allifs)
766 {
767 nvlist_t *nvl = NULL;
768 size_t nvlsize, bufsize;
769 ipmgmt_initif_arg_t *iargp;
770 char *buf = NULL, *nvlbuf = NULL;
771 ipmgmt_get_rval_t *rvalp = NULL;
772 int err;
773 ipadm_status_t status = IPADM_SUCCESS;
774
775 if ((err = ipadm_str2nvlist(ifs, &nvl, IPADM_NORVAL)) != 0)
776 return (ipadm_errno2status(err));
933 * to new buffer.
934 */
935 if (err == 0) {
936 void *newp;
937
938 /* allocated memory will be freed by the caller */
939 if ((newp = realloc(*rbufp, darg.rsize)) == NULL) {
940 err = ENOMEM;
941 } else {
942 *rbufp = newp;
943 (void) memcpy(*rbufp, darg.rbuf, darg.rsize);
944 }
945 }
946 /* munmap() the door buffer */
947 (void) munmap(darg.rbuf, darg.rsize);
948 } else {
949 if (darg.rsize != rsize)
950 err = EBADE;
951 }
952 return (err);
953 }
954
955 /*
956 * A helper that is used by i_ipadm_get_db_addr and i_ipadm_get_db_if
957 * to do a door_call to ipmgmtd, that should return persistent information
958 * about interfaces or/and addresses from ipadm DB
959 */
960 ipadm_status_t
961 i_ipadm_call_ipmgmtd(ipadm_handle_t iph, void *garg,
962 size_t garg_size, nvlist_t **onvl)
963 {
964 ipmgmt_get_rval_t *rvalp;
965 int err;
966 size_t nvlsize;
967 char *nvlbuf;
968
969 rvalp = malloc(sizeof (ipmgmt_get_rval_t));
970 err = ipadm_door_call(iph, garg, garg_size, (void **)&rvalp,
971 sizeof (*rvalp), B_TRUE);
972 if (err == 0) {
973 nvlsize = rvalp->ir_nvlsize;
974 nvlbuf = (char *)rvalp + sizeof (ipmgmt_get_rval_t);
975 err = nvlist_unpack(nvlbuf, nvlsize, onvl, NV_ENCODE_NATIVE);
976 }
977 free(rvalp);
978
979 return (ipadm_errno2status(err));
980 }
|