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); }