/* ARGSUSED */
static int
ip_getlifaddr_impl(sa_family_t family, phy_if_t phy_ifdata,
    lif_if_t ifdata, size_t nelem, net_ifaddr_t type[],
    struct sockaddr *storage, ip_stack_t *ipst)
{
	struct sockaddr_in6 *sin6;
	struct sockaddr_in *sin;
	lif_if_t ipifid;
	ipif_t *ipif;
	int i;

	ASSERT(type != NULL);
	ASSERT(storage != NULL);

	ipifid = UNMAP_IPIF_ID(ifdata);

	if (family == AF_INET) {
		if ((ipif = ipif_getby_indexes((uint_t)phy_ifdata,
		    (uint_t)ipifid, B_FALSE, ipst)) == NULL)
			return (1);

		sin = (struct sockaddr_in *)storage;
		for (i = 0; i < nelem; i++, sin++) {
			if (ip_getifaddr_type(AF_INET, ipif, type[i],
			    &sin->sin_addr) < 0) {
				ip2dbg(("ip_getlifaddr_impl failed type %d\n",
				    type[i]));
				ipif_refrele(ipif);
				return (1);
			}
			sin->sin_family = AF_INET;
		}
	} else {
		if ((ipif = ipif_getby_indexes((uint_t)phy_ifdata,
		    (uint_t)ipifid, B_TRUE, ipst)) == NULL)
			return (1);

		sin6 = (struct sockaddr_in6 *)storage;
		for (i = 0; i < nelem; i++, sin6++) {
			if (ip_getifaddr_type(AF_INET6, ipif, type[i],
			    &sin6->sin6_addr) < 0) {
				ip2dbg(("ip_getlifaddr_impl failed type %d\n",
				    type[i]));
				ipif_refrele(ipif);
				return (1);
			}
			sin6->sin6_family = AF_INET6;
		}
	}
	ipif_refrele(ipif);
	return (0);
}
/* ARGSUSED */
static int
ip_getmtu_impl(phy_if_t phy_ifdata, lif_if_t ifdata, boolean_t isv6,
    ip_stack_t *ipst)
{
	lif_if_t ipifid;
	ipif_t *ipif;
	int mtu;

	ipifid = UNMAP_IPIF_ID(ifdata);

	ipif = ipif_getby_indexes((uint_t)phy_ifdata, (uint_t)ipifid,
	    isv6, ipst);
	if (ipif == NULL)
		return (0);

	mtu = ipif->ipif_ill->ill_mtu;
	ipif_refrele(ipif);

	if (mtu == 0) {
		ill_t *ill;

		if ((ill = ill_lookup_on_ifindex((uint_t)phy_ifdata, isv6,
		    ipst)) == NULL) {
			return (0);
		}
		mtu = ill->ill_mtu;
		ill_refrele(ill);
	}

	return (mtu);
}
/*
 * Shared implementation to get next interface from the current list of
 * logical network interfaces
 */
static lif_if_t
ip_lifgetnext_impl(phy_if_t phy_ifdata, lif_if_t ifdata, boolean_t isv6,
    ip_stack_t *ipst)
{
	lif_if_t newidx, oldidx;
	boolean_t nextok;
	ipif_t *ipif;
	ill_t *ill;

	ill = ill_lookup_on_ifindex(phy_ifdata, isv6, ipst);
	if (ill == NULL)
		return (0);

	if (ifdata != 0) {
		oldidx = UNMAP_IPIF_ID(ifdata);
		nextok = B_FALSE;
	} else {
		oldidx = 0;
		nextok = B_TRUE;
	}

	mutex_enter(&ill->ill_lock);
	if (ill->ill_state_flags & ILL_CONDEMNED) {
		mutex_exit(&ill->ill_lock);
		ill_refrele(ill);
		return (0);
	}

	/*
	 * It's safe to iterate the ill_ipif list when holding an ill_lock.
	 * And it's also safe to access ipif_id without ipif refhold.
	 * See the field access rules in ip.h.
	 */
	for (ipif = ill->ill_ipif; ipif != NULL; ipif = ipif->ipif_next) {
		if (!IPIF_CAN_LOOKUP(ipif))
			continue;
		if (nextok) {
			ipif_refhold_locked(ipif);
			break;
		} else if (oldidx == ipif->ipif_id) {
			nextok = B_TRUE;
		}
	}

	mutex_exit(&ill->ill_lock);
	ill_refrele(ill);

	if (ipif == NULL)
		return (0);

	newidx = ipif->ipif_id;
	ipif_refrele(ipif);

	return (MAP_IPIF_ID(newidx));
}
/*
 * Shared implementation to determine the zoneid associated with an IPv4/IPv6
 * address
 */
static int
ip_getlifzone_impl(sa_family_t family, phy_if_t phy_ifdata, lif_if_t ifdata,
    ip_stack_t *ipst, zoneid_t *zoneid)
{
	ipif_t  *ipif;

	ipif = ipif_getby_indexes((uint_t)phy_ifdata,
	    UNMAP_IPIF_ID((uint_t)ifdata), (family == AF_INET6), ipst);
	if (ipif == NULL)
		return (-1);
	*zoneid = IP_REAL_ZONEID(ipif->ipif_zoneid, ipst);
	ipif_refrele(ipif);
	return (0);
}
/*
 * The behaviour here mirrors that for the SIOCFLIFFLAGS ioctl where the
 * union of all of the relevant flags is returned.
 */
static int
ip_getlifflags_impl(sa_family_t family, phy_if_t phy_ifdata, lif_if_t ifdata,
    ip_stack_t *ipst, uint64_t *flags)
{
	phyint_t *phyi;
	ipif_t *ipif;
	ill_t *ill;

	ill = ill_lookup_on_ifindex(phy_ifdata, (family == AF_INET6), ipst);
	if (ill == NULL)
		return (-1);
	phyi = ill->ill_phyint;

	ipif = ipif_getby_indexes((uint_t)phy_ifdata,
	    UNMAP_IPIF_ID((uint_t)ifdata), (family == AF_INET6), ipst);
	if (ipif == NULL) {
		ill_refrele(ill);
		return (-1);
	}
	*flags = ipif->ipif_flags | ill->ill_flags | phyi->phyint_flags;
	ipif_refrele(ipif);
	ill_refrele(ill);
	return (0);
}
Exemple #6
0
int
ibcm_resolver_pr_lookup(ibcm_arp_streams_t *ib_s, ibt_ip_addr_t *dst_addr,
    ibt_ip_addr_t *src_addr, zoneid_t myzoneid)
{
	ibcm_arp_prwqn_t *wqnp;
	ire_t	*ire = NULL;
	ipif_t	*ipif = NULL;
	ill_t	*ill = NULL;
	ill_t	*hwaddr_ill = NULL;
	ip_stack_t *ipst;
	ipaddr_t	setsrcv4;
	in6_addr_t	setsrcv6;

	IBCM_PRINT_IP("ibcm_arp_pr_lookup: SRC", src_addr);
	IBCM_PRINT_IP("ibcm_arp_pr_lookup: DST", dst_addr);

	if ((wqnp = ibcm_arp_create_prwqn(ib_s, dst_addr, src_addr)) == NULL) {
		IBTF_DPRINTF_L2(cmlog, "ibcm_resolver_pr_lookup: "
		    "ibcm_arp_create_prwqn failed");
		ib_s->status = ENOMEM;
		return (1);
	}

	ipst = netstack_find_by_zoneid(myzoneid)->netstack_ip;
	if (dst_addr->family == AF_INET) {
		/*
		 * get an ire for the destination adress.
		 * Note that we can't use MATCH_IRE_ILL since that would
		 * require that the first ill we find have ire_ill set.
		 */
		setsrcv4 = INADDR_ANY;
		ire = ire_route_recursive_v4(dst_addr->un.ip4addr, 0, NULL,
		    myzoneid, NULL, MATCH_IRE_DSTONLY, B_TRUE, 0, ipst,
		    &setsrcv4, NULL, NULL);

		ASSERT(ire != NULL);
		if (ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
			IBTF_DPRINTF_L2(cmlog, "ibcm_resolver_pr_lookup: "
			    "ire_route_recursive_v4 failed");
			ib_s->status = EFAULT;
			goto fail;
		}
		ill = ire_nexthop_ill(ire);
		if (ill == NULL) {
			IBTF_DPRINTF_L2(cmlog, "ibcm_resolver_pr_lookup: "
			    "ire_nexthop_ill failed");
			ib_s->status = EFAULT;
			goto fail;
		}

		/* Pick a source address */
		if (ip_select_source_v4(ill, setsrcv4, dst_addr->un.ip4addr,
		    INADDR_ANY, myzoneid, ipst, &wqnp->src_addr.un.ip4addr,
		    NULL, NULL) != 0) {
			ib_s->status = EADDRNOTAVAIL;
			goto fail;
		}

		wqnp->gateway.un.ip4addr = ire->ire_gateway_addr;
		wqnp->netmask.un.ip4addr = ire->ire_mask;
		wqnp->src_addr.family = wqnp->gateway.family =
		    wqnp->netmask.family = AF_INET;

	} else if (dst_addr->family == AF_INET6) {
		/*
		 * get an ire for the destination adress.
		 * Note that we can't use MATCH_IRE_ILL since that would
		 * require that the first ill we find have ire_ill set. Thus
		 * we compare ire_ill against ipif_ill after the lookup.
		 */
		setsrcv6 = ipv6_all_zeros;
		ire = ire_route_recursive_v6(&dst_addr->un.ip6addr, 0, NULL,
		    myzoneid, NULL, MATCH_IRE_DSTONLY, B_TRUE, 0, ipst,
		    &setsrcv6, NULL, NULL);

		ASSERT(ire != NULL);
		if (ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
			IBTF_DPRINTF_L2(cmlog, "ibcm_resolver_pr_lookup: "
			    "ire_route_recursive_v6 failed");
			ib_s->status = EFAULT;
			goto fail;
		}
		ill = ire_nexthop_ill(ire);
		if (ill == NULL) {
			IBTF_DPRINTF_L2(cmlog, "ibcm_resolver_pr_lookup: "
			    "ire_nexthop_ill failed");
			ib_s->status = EFAULT;
			goto fail;
		}

		/* Pick a source address */
		if (ip_select_source_v6(ill, &setsrcv6, &dst_addr->un.ip6addr,
		    myzoneid, ipst, B_FALSE, IPV6_PREFER_SRC_DEFAULT,
		    &wqnp->src_addr.un.ip6addr, NULL, NULL) != 0) {
			ib_s->status = EADDRNOTAVAIL;
			goto fail;
		}

		wqnp->gateway.un.ip6addr = ire->ire_gateway_addr_v6;
		wqnp->netmask.un.ip6addr = ire->ire_mask_v6;
		wqnp->src_addr.family = wqnp->gateway.family =
		    wqnp->netmask.family = AF_INET6;
	}

	(void) strlcpy(wqnp->ifname, ill->ill_name, sizeof (wqnp->ifname));

	/*
	 * For IPMP data addresses, we need to use the hardware address of the
	 * interface bound to the given address.
	 */
	if (IS_IPMP(ill)) {
		if (wqnp->src_addr.family == AF_INET) {
			ipif = ipif_lookup_addr(wqnp->src_addr.un.ip4addr, ill,
			    myzoneid, ipst);
		} else {
			ipif = ipif_lookup_addr_v6(&wqnp->src_addr.un.ip6addr,
			    ill, myzoneid, ipst);
		}
		if (ipif == NULL) {
			ib_s->status = ENETUNREACH;
			goto fail;
		}

		if ((hwaddr_ill = ipmp_ipif_hold_bound_ill(ipif)) == NULL) {
			IBTF_DPRINTF_L2(cmlog, "ibcm_resolver_pr_lookup: "
			    "no bound ill for IPMP interface %s",
			    ill->ill_name);
			ib_s->status = EFAULT;
			goto fail;
		}
	} else {
		hwaddr_ill = ill;
		ill_refhold(hwaddr_ill);	/* for symmetry */
	}

	if ((ib_s->status = ibcm_arp_check_interface(hwaddr_ill)) != 0) {
		IBTF_DPRINTF_L2(cmlog, "ibcm_resolver_pr_lookup: "
		    "ibcm_arp_check_interface failed");
		goto fail;
	}

	bcopy(hwaddr_ill->ill_phys_addr, &wqnp->src_mac,
	    hwaddr_ill->ill_phys_addr_length);

	IBTF_DPRINTF_L4(cmlog, "ibcm_resolver_pr_lookup: outgoing if:%s",
	    wqnp->ifname);

	/*
	 * at this stage, we have the source address and the IB
	 * interface, now get the destination mac address from
	 * arp or ipv6 drivers
	 */
	ib_s->status = ibcm_nce_lookup(wqnp, ill, myzoneid);
	if (ib_s->status != 0) {
		IBTF_DPRINTF_L2(cmlog, "ibcm_resolver_pr_lookup: "
		    "ibcm_nce_lookup failed: %d", ib_s->status);
		goto fail;
	}

	ill_refrele(hwaddr_ill);
	ill_refrele(ill);
	ire_refrele(ire);
	if (ipif != NULL)
		ipif_refrele(ipif);
	netstack_rele(ipst->ips_netstack);

	IBTF_DPRINTF_L4(cmlog, "ibcm_resolver_pr_lookup: Return: 0x%p", wqnp);
	return (0);
fail:
	if (hwaddr_ill != NULL)
		ill_refrele(hwaddr_ill);
	if (ill != NULL)
		ill_refrele(ill);
	if (ire != NULL)
		ire_refrele(ire);
	if (ipif != NULL)
		ipif_refrele(ipif);
	ibcm_arp_delete_prwqn(wqnp);
	netstack_rele(ipst->ips_netstack);
	return (1);
}
int
ibcm_resolver_pr_lookup(ibcm_arp_streams_t *ib_s, ibt_ip_addr_t *dst_addr,
    ibt_ip_addr_t *src_addr)
{
	ibcm_arp_prwqn_t *wqnp;
	ire_t	*ire = NULL;
	ipif_t	*ipif = NULL;
	ill_t	*ill = NULL;
	ill_t	*hwaddr_ill = NULL;
	ip_stack_t *ipst;
	int		len;
	ipaddr_t	setsrcv4;
	in6_addr_t	setsrcv6;

	IBCM_PRINT_IP("ibcm_arp_pr_lookup: SRC", src_addr);
	IBCM_PRINT_IP("ibcm_arp_pr_lookup: DST", dst_addr);

	if ((wqnp = ibcm_arp_create_prwqn(ib_s, dst_addr, src_addr)) == NULL) {
		IBTF_DPRINTF_L2(cmlog, "ibcm_resolver_pr_lookup: "
		    "ibcm_arp_create_prwqn failed");
		ib_s->status = ENOMEM;
		return (1);
	}

	ipst = netstack_find_by_zoneid(GLOBAL_ZONEID)->netstack_ip;
	if (dst_addr->family == AF_INET) {
		/*
		 * A local address is always specified, and it is used
		 * to find the zoneid.
		 */
		ipif = ipif_lookup_addr(src_addr->un.ip4addr, NULL, ALL_ZONES,
		    ipst);
		if (ipif == NULL) {
			IBTF_DPRINTF_L2(cmlog, "ibcm_resolver_pr_lookup: "
			    "ipif_lookup_addr failed");
			ib_s->status = EFAULT;
			goto fail;
		}

		/*
		 * get an ire for the destination adress.
		 * Note that we can't use MATCH_IRE_ILL since that would
		 * require that the first ill we find have ire_ill set. Thus
		 * we compare ire_ill against ipif_ill after the lookup.
		 */
		setsrcv4 = INADDR_ANY;
		ire = ire_route_recursive_v4(dst_addr->un.ip4addr, 0, NULL,
		    ipif->ipif_zoneid, NULL, MATCH_IRE_DSTONLY, B_TRUE, 0, ipst,
		    &setsrcv4, NULL, NULL);

		ASSERT(ire != NULL);
		if (ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
			IBTF_DPRINTF_L2(cmlog, "ibcm_resolver_pr_lookup: "
			    "ire_route_recursive_v4 failed");
			ib_s->status = EFAULT;
			goto fail;
		}
		ill = ire_nexthop_ill(ire);
		if (ill == NULL) {
			IBTF_DPRINTF_L2(cmlog, "ibcm_resolver_pr_lookup: "
			    "ire_nexthop_ill failed");
			ib_s->status = EFAULT;
			goto fail;
		}
		if (ill != ipif->ipif_ill) {
			IBTF_DPRINTF_L2(cmlog, "ibcm_resolver_pr_lookup: "
			    "wrong ill");
			ib_s->status = EFAULT;
			goto fail;
		}

		wqnp->gateway.un.ip4addr = ire->ire_gateway_addr;
		wqnp->netmask.un.ip4addr = ire->ire_mask;
		wqnp->src_addr.un.ip4addr = src_addr->un.ip4addr;
		wqnp->src_addr.family = wqnp->gateway.family =
		    wqnp->netmask.family = AF_INET;

	} else if (dst_addr->family == AF_INET6) {
		/*
		 * A local address is always specified, and it is used
		 * to find the zoneid.
		 * We should really match on scopeid for link locals here.
		 */
		ipif = ipif_lookup_addr_v6(&src_addr->un.ip6addr, NULL,
		    ALL_ZONES, ipst);
		if (ipif == NULL) {
			IBTF_DPRINTF_L2(cmlog, "ibcm_resolver_pr_lookup: "
			    "ipif_lookup_addr_v6 failed");
			ib_s->status = EFAULT;
			goto fail;
		}

		/*
		 * get an ire for the destination adress.
		 * Note that we can't use MATCH_IRE_ILL since that would
		 * require that the first ill we find have ire_ill set. Thus
		 * we compare ire_ill against ipif_ill after the lookup.
		 */
		setsrcv6 = ipv6_all_zeros;
		ire = ire_route_recursive_v6(&dst_addr->un.ip6addr, 0, NULL,
		    ipif->ipif_zoneid, NULL, MATCH_IRE_DSTONLY, B_TRUE, 0, ipst,
		    &setsrcv6, NULL, NULL);

		ASSERT(ire != NULL);
		if (ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
			IBTF_DPRINTF_L2(cmlog, "ibcm_resolver_pr_lookup: "
			    "ire_route_recursive_v6 failed");
			ib_s->status = EFAULT;
			goto fail;
		}
		ill = ire_nexthop_ill(ire);
		if (ill == NULL) {
			IBTF_DPRINTF_L2(cmlog, "ibcm_resolver_pr_lookup: "
			    "ire_nexthop_ill failed");
			ib_s->status = EFAULT;
			goto fail;
		}

		if (ill != ipif->ipif_ill) {
			IBTF_DPRINTF_L2(cmlog, "ibcm_resolver_pr_lookup: "
			    "wrong ill");
			ib_s->status = EFAULT;
			goto fail;
		}

		wqnp->gateway.un.ip6addr = ire->ire_gateway_addr_v6;
		wqnp->netmask.un.ip6addr = ire->ire_mask_v6;
		wqnp->src_addr.un.ip6addr = src_addr->un.ip6addr;
		wqnp->src_addr.family = wqnp->gateway.family =
		    wqnp->netmask.family = AF_INET6;
	}

	(void) strlcpy(wqnp->ifname, ill->ill_name, sizeof (wqnp->ifname));

	/*
	 * For IPMP data addresses, we need to use the hardware address of the
	 * interface bound to the given address.
	 */
	if (IS_IPMP(ill)) {
		if ((hwaddr_ill = ipmp_ipif_hold_bound_ill(ipif)) == NULL) {
			IBTF_DPRINTF_L2(cmlog, "ibcm_resolver_pr_lookup: "
			    "no bound ill for IPMP interface %s",
			    ill->ill_name);
			ib_s->status = EFAULT;
			goto fail;
		}
	} else {
		hwaddr_ill = ill;
		ill_refhold(hwaddr_ill);	/* for symmetry */
	}

	if ((ib_s->status = ibcm_arp_check_interface(hwaddr_ill)) != 0) {
		IBTF_DPRINTF_L2(cmlog, "ibcm_resolver_pr_lookup: "
		    "ibcm_arp_check_interface failed");
		goto fail;
	}

	bcopy(hwaddr_ill->ill_phys_addr, &wqnp->src_mac,
	    hwaddr_ill->ill_phys_addr_length);

	IBTF_DPRINTF_L4(cmlog, "ibcm_resolver_pr_lookup: outgoing if:%s",
	    wqnp->ifname);

	/*
	 * if the user supplied a address, then verify rts returned
	 * the same address
	 */
	if (wqnp->usrc_addr.family) {
		len = (wqnp->usrc_addr.family == AF_INET) ?
		    IP_ADDR_LEN : sizeof (in6_addr_t);
		if (bcmp(&wqnp->usrc_addr.un, &wqnp->src_addr.un, len)) {
			IBTF_DPRINTF_L2(cmlog, "ibcm_resolver_pr_lookup: "
			    "srcaddr mismatch:%d", ENETUNREACH);
			goto fail;
		}
	}

	/*
	 * at this stage, we have the source address and the IB
	 * interface, now get the destination mac address from
	 * arp or ipv6 drivers
	 */
	ib_s->status = ibcm_nce_lookup(wqnp, ill, getzoneid());
	if (ib_s->status != 0) {
		IBTF_DPRINTF_L2(cmlog, "ibcm_resolver_pr_lookup: "
		    "ibcm_nce_lookup failed: %d", ib_s->status);
		goto fail;
	}

	ill_refrele(hwaddr_ill);
	ill_refrele(ill);
	ire_refrele(ire);
	ipif_refrele(ipif);
	netstack_rele(ipst->ips_netstack);

	IBTF_DPRINTF_L4(cmlog, "ibcm_resolver_pr_lookup: Return: 0x%p", wqnp);
	return (0);
fail:
	if (hwaddr_ill != NULL)
		ill_refrele(hwaddr_ill);
	if (ill != NULL)
		ill_refrele(ill);
	if (ire != NULL)
		ire_refrele(ire);
	if (ipif != NULL)
		ipif_refrele(ipif);
	ibcm_arp_delete_prwqn(wqnp);
	netstack_rele(ipst->ips_netstack);
	return (1);
}