17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 545916cd2Sjpk * Common Development and Distribution License (the "License"). 645916cd2Sjpk * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22550b6e40SSowmini Varadhan * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. 237c478bd9Sstevel@tonic-gate * Copyright (c) 1990 Mentat Inc. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * This file contains the interface control functions for IPv6. 287c478bd9Sstevel@tonic-gate */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <sys/types.h> 317c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 327c478bd9Sstevel@tonic-gate #include <sys/stream.h> 337c478bd9Sstevel@tonic-gate #include <sys/dlpi.h> 347c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 357c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 367c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 377c478bd9Sstevel@tonic-gate #include <sys/kstat.h> 387c478bd9Sstevel@tonic-gate #include <sys/debug.h> 397c478bd9Sstevel@tonic-gate #include <sys/zone.h> 40f4b3ec61Sdh155122 #include <sys/policy.h> 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #include <sys/systm.h> 437c478bd9Sstevel@tonic-gate #include <sys/param.h> 447c478bd9Sstevel@tonic-gate #include <sys/socket.h> 457c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h> 467c478bd9Sstevel@tonic-gate #include <net/if.h> 477c478bd9Sstevel@tonic-gate #include <net/if_dl.h> 487c478bd9Sstevel@tonic-gate #include <net/route.h> 497c478bd9Sstevel@tonic-gate #include <netinet/in.h> 507c478bd9Sstevel@tonic-gate #include <netinet/igmp_var.h> 517c478bd9Sstevel@tonic-gate #include <netinet/ip6.h> 527c478bd9Sstevel@tonic-gate #include <netinet/icmp6.h> 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate #include <inet/common.h> 557c478bd9Sstevel@tonic-gate #include <inet/nd.h> 566e91bba0SGirish Moodalbail #include <inet/tunables.h> 577c478bd9Sstevel@tonic-gate #include <inet/mib2.h> 587c478bd9Sstevel@tonic-gate #include <inet/ip.h> 597c478bd9Sstevel@tonic-gate #include <inet/ip6.h> 607c478bd9Sstevel@tonic-gate #include <inet/ip_multi.h> 617c478bd9Sstevel@tonic-gate #include <inet/ip_ire.h> 627c478bd9Sstevel@tonic-gate #include <inet/ip_rts.h> 637c478bd9Sstevel@tonic-gate #include <inet/ip_ndp.h> 647c478bd9Sstevel@tonic-gate #include <inet/ip_if.h> 657c478bd9Sstevel@tonic-gate #include <inet/ip6_asp.h> 667c478bd9Sstevel@tonic-gate #include <inet/ipclassifier.h> 677c478bd9Sstevel@tonic-gate #include <inet/sctp_ip.h> 687c478bd9Sstevel@tonic-gate 6945916cd2Sjpk #include <sys/tsol/tndb.h> 7045916cd2Sjpk #include <sys/tsol/tnet.h> 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate static in6_addr_t ipv6_ll_template = 737c478bd9Sstevel@tonic-gate {(uint32_t)V6_LINKLOCAL, 0x0, 0x0, 0x0}; 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate static ipif_t * 767c478bd9Sstevel@tonic-gate ipif_lookup_interface_v6(const in6_addr_t *if_addr, const in6_addr_t *dst, 77bd670b35SErik Nordmark ip_stack_t *ipst); 78bd670b35SErik Nordmark 79bd670b35SErik Nordmark static int ipif_add_ires_v6(ipif_t *, boolean_t); 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate /* 82bd670b35SErik Nordmark * This function is called when an application does not specify an interface 83bd670b35SErik Nordmark * to be used for multicast traffic. It calls ire_lookup_multi_v6() to look 8448de1bd2Skcpoon * for an interface route for the specified multicast group. Doing 8548de1bd2Skcpoon * this allows the administrator to add prefix routes for multicast to 8648de1bd2Skcpoon * indicate which interface to be used for multicast traffic in the above 8748de1bd2Skcpoon * scenario. The route could be for all multicast (ff00::/8), for a single 8848de1bd2Skcpoon * multicast group (a /128 route) or anything in between. If there is no 8948de1bd2Skcpoon * such multicast route, we just find any multicast capable interface and 9048de1bd2Skcpoon * return it. 91bd670b35SErik Nordmark * 92bd670b35SErik Nordmark * We support MULTIRT and RTF_SETSRC on the multicast routes added to the 93bd670b35SErik Nordmark * unicast table. This is used by CGTP. 947c478bd9Sstevel@tonic-gate */ 957c478bd9Sstevel@tonic-gate ill_t * 96bd670b35SErik Nordmark ill_lookup_group_v6(const in6_addr_t *group, zoneid_t zoneid, ip_stack_t *ipst, 97bd670b35SErik Nordmark boolean_t *multirtp, in6_addr_t *setsrcp) 987c478bd9Sstevel@tonic-gate { 997c478bd9Sstevel@tonic-gate ill_t *ill; 1007c478bd9Sstevel@tonic-gate 101bd670b35SErik Nordmark ill = ire_lookup_multi_ill_v6(group, zoneid, ipst, multirtp, setsrcp); 102bd670b35SErik Nordmark if (ill != NULL) 1037c478bd9Sstevel@tonic-gate return (ill); 1047c478bd9Sstevel@tonic-gate 105bd670b35SErik Nordmark return (ill_lookup_multicast(ipst, zoneid, B_TRUE)); 10648de1bd2Skcpoon } 10748de1bd2Skcpoon 1087c478bd9Sstevel@tonic-gate /* 1097c478bd9Sstevel@tonic-gate * Look for an ipif with the specified interface address and destination. 1107c478bd9Sstevel@tonic-gate * The destination address is used only for matching point-to-point interfaces. 1117c478bd9Sstevel@tonic-gate */ 1127c478bd9Sstevel@tonic-gate static ipif_t * 1137c478bd9Sstevel@tonic-gate ipif_lookup_interface_v6(const in6_addr_t *if_addr, const in6_addr_t *dst, 114bd670b35SErik Nordmark ip_stack_t *ipst) 1157c478bd9Sstevel@tonic-gate { 1167c478bd9Sstevel@tonic-gate ipif_t *ipif; 1177c478bd9Sstevel@tonic-gate ill_t *ill; 1187c478bd9Sstevel@tonic-gate ill_walk_context_t ctx; 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate /* 1217c478bd9Sstevel@tonic-gate * First match all the point-to-point interfaces 1227c478bd9Sstevel@tonic-gate * before looking at non-point-to-point interfaces. 1237c478bd9Sstevel@tonic-gate * This is done to avoid returning non-point-to-point 1247c478bd9Sstevel@tonic-gate * ipif instead of unnumbered point-to-point ipif. 1257c478bd9Sstevel@tonic-gate */ 126f4b3ec61Sdh155122 rw_enter(&ipst->ips_ill_g_lock, RW_READER); 127f4b3ec61Sdh155122 ill = ILL_START_WALK_V6(&ctx, ipst); 1287c478bd9Sstevel@tonic-gate for (; ill != NULL; ill = ill_next(&ctx, ill)) { 1297c478bd9Sstevel@tonic-gate mutex_enter(&ill->ill_lock); 1305597b60aSnordmark for (ipif = ill->ill_ipif; ipif != NULL; 1315597b60aSnordmark ipif = ipif->ipif_next) { 1327c478bd9Sstevel@tonic-gate /* Allow the ipif to be down */ 1337c478bd9Sstevel@tonic-gate if ((ipif->ipif_flags & IPIF_POINTOPOINT) && 1347c478bd9Sstevel@tonic-gate (IN6_ARE_ADDR_EQUAL(&ipif->ipif_v6lcl_addr, 1357c478bd9Sstevel@tonic-gate if_addr)) && 1367c478bd9Sstevel@tonic-gate (IN6_ARE_ADDR_EQUAL(&ipif->ipif_v6pp_dst_addr, 1377c478bd9Sstevel@tonic-gate dst))) { 138bd670b35SErik Nordmark if (!IPIF_IS_CONDEMNED(ipif)) { 1397c478bd9Sstevel@tonic-gate ipif_refhold_locked(ipif); 1407c478bd9Sstevel@tonic-gate mutex_exit(&ill->ill_lock); 141f4b3ec61Sdh155122 rw_exit(&ipst->ips_ill_g_lock); 1427c478bd9Sstevel@tonic-gate return (ipif); 1437c478bd9Sstevel@tonic-gate } 1447c478bd9Sstevel@tonic-gate } 1457c478bd9Sstevel@tonic-gate } 1467c478bd9Sstevel@tonic-gate mutex_exit(&ill->ill_lock); 1477c478bd9Sstevel@tonic-gate } 148f4b3ec61Sdh155122 rw_exit(&ipst->ips_ill_g_lock); 1497c478bd9Sstevel@tonic-gate /* lookup the ipif based on interface address */ 150bd670b35SErik Nordmark ipif = ipif_lookup_addr_v6(if_addr, NULL, ALL_ZONES, ipst); 1517c478bd9Sstevel@tonic-gate ASSERT(ipif == NULL || ipif->ipif_isv6); 1527c478bd9Sstevel@tonic-gate return (ipif); 1537c478bd9Sstevel@tonic-gate } 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate /* 156e11c3f44Smeem * Common function for ipif_lookup_addr_v6() and ipif_lookup_addr_exact_v6(). 1577c478bd9Sstevel@tonic-gate */ 158e11c3f44Smeem static ipif_t * 159e11c3f44Smeem ipif_lookup_addr_common_v6(const in6_addr_t *addr, ill_t *match_ill, 160bd670b35SErik Nordmark uint32_t match_flags, zoneid_t zoneid, ip_stack_t *ipst) 1617c478bd9Sstevel@tonic-gate { 1627c478bd9Sstevel@tonic-gate ipif_t *ipif; 1637c478bd9Sstevel@tonic-gate ill_t *ill; 1647c478bd9Sstevel@tonic-gate boolean_t ptp = B_FALSE; 1657c478bd9Sstevel@tonic-gate ill_walk_context_t ctx; 166bd670b35SErik Nordmark boolean_t match_illgrp = (match_flags & IPIF_MATCH_ILLGRP); 167bd670b35SErik Nordmark boolean_t no_duplicate = (match_flags & IPIF_MATCH_NONDUP); 1687c478bd9Sstevel@tonic-gate 169f4b3ec61Sdh155122 rw_enter(&ipst->ips_ill_g_lock, RW_READER); 1707c478bd9Sstevel@tonic-gate /* 1717c478bd9Sstevel@tonic-gate * Repeat twice, first based on local addresses and 1727c478bd9Sstevel@tonic-gate * next time for pointopoint. 1737c478bd9Sstevel@tonic-gate */ 1747c478bd9Sstevel@tonic-gate repeat: 175f4b3ec61Sdh155122 ill = ILL_START_WALK_V6(&ctx, ipst); 1767c478bd9Sstevel@tonic-gate for (; ill != NULL; ill = ill_next(&ctx, ill)) { 177e11c3f44Smeem if (match_ill != NULL && ill != match_ill && 178e11c3f44Smeem (!match_illgrp || !IS_IN_SAME_ILLGRP(ill, match_ill))) { 1797c478bd9Sstevel@tonic-gate continue; 1807c478bd9Sstevel@tonic-gate } 1817c478bd9Sstevel@tonic-gate mutex_enter(&ill->ill_lock); 1825597b60aSnordmark for (ipif = ill->ill_ipif; ipif != NULL; 1835597b60aSnordmark ipif = ipif->ipif_next) { 18445916cd2Sjpk if (zoneid != ALL_ZONES && 18545916cd2Sjpk ipif->ipif_zoneid != zoneid && 18645916cd2Sjpk ipif->ipif_zoneid != ALL_ZONES) 1877c478bd9Sstevel@tonic-gate continue; 188bd670b35SErik Nordmark 189bd670b35SErik Nordmark if (no_duplicate && 190bd670b35SErik Nordmark !(ipif->ipif_flags & IPIF_UP)) { 191bd670b35SErik Nordmark continue; 192bd670b35SErik Nordmark } 193bd670b35SErik Nordmark 1947c478bd9Sstevel@tonic-gate /* Allow the ipif to be down */ 1957c478bd9Sstevel@tonic-gate if ((!ptp && (IN6_ARE_ADDR_EQUAL( 1967c478bd9Sstevel@tonic-gate &ipif->ipif_v6lcl_addr, addr) && 1977c478bd9Sstevel@tonic-gate (ipif->ipif_flags & IPIF_UNNUMBERED) == 0)) || 1987c478bd9Sstevel@tonic-gate (ptp && (ipif->ipif_flags & IPIF_POINTOPOINT) && 1997c478bd9Sstevel@tonic-gate IN6_ARE_ADDR_EQUAL(&ipif->ipif_v6pp_dst_addr, 2007c478bd9Sstevel@tonic-gate addr))) { 201bd670b35SErik Nordmark if (!IPIF_IS_CONDEMNED(ipif)) { 2027c478bd9Sstevel@tonic-gate ipif_refhold_locked(ipif); 2037c478bd9Sstevel@tonic-gate mutex_exit(&ill->ill_lock); 204f4b3ec61Sdh155122 rw_exit(&ipst->ips_ill_g_lock); 2057c478bd9Sstevel@tonic-gate return (ipif); 2067c478bd9Sstevel@tonic-gate } 2077c478bd9Sstevel@tonic-gate } 2087c478bd9Sstevel@tonic-gate } 2097c478bd9Sstevel@tonic-gate mutex_exit(&ill->ill_lock); 2107c478bd9Sstevel@tonic-gate } 2117c478bd9Sstevel@tonic-gate 2125597b60aSnordmark /* If we already did the ptp case, then we are done */ 2137c478bd9Sstevel@tonic-gate if (ptp) { 214f4b3ec61Sdh155122 rw_exit(&ipst->ips_ill_g_lock); 2157c478bd9Sstevel@tonic-gate return (NULL); 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate ptp = B_TRUE; 2187c478bd9Sstevel@tonic-gate goto repeat; 2197c478bd9Sstevel@tonic-gate } 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate /* 222e11c3f44Smeem * Lookup an ipif with the specified address. For point-to-point links we 223e11c3f44Smeem * look for matches on either the destination address or the local address, 224e11c3f44Smeem * but we skip the local address check if IPIF_UNNUMBERED is set. If the 225e11c3f44Smeem * `match_ill' argument is non-NULL, the lookup is restricted to that ill 226e11c3f44Smeem * (or illgrp if `match_ill' is in an IPMP group). 227e11c3f44Smeem */ 228e11c3f44Smeem ipif_t * 229e11c3f44Smeem ipif_lookup_addr_v6(const in6_addr_t *addr, ill_t *match_ill, zoneid_t zoneid, 230bd670b35SErik Nordmark ip_stack_t *ipst) 231e11c3f44Smeem { 232bd670b35SErik Nordmark return (ipif_lookup_addr_common_v6(addr, match_ill, IPIF_MATCH_ILLGRP, 233bd670b35SErik Nordmark zoneid, ipst)); 234bd670b35SErik Nordmark } 235bd670b35SErik Nordmark 236bd670b35SErik Nordmark /* 237bd670b35SErik Nordmark * Lookup an ipif with the specified address. Similar to ipif_lookup_addr, 238bd670b35SErik Nordmark * except that we will only return an address if it is not marked as 239bd670b35SErik Nordmark * IPIF_DUPLICATE 240bd670b35SErik Nordmark */ 241bd670b35SErik Nordmark ipif_t * 242bd670b35SErik Nordmark ipif_lookup_addr_nondup_v6(const in6_addr_t *addr, ill_t *match_ill, 243bd670b35SErik Nordmark zoneid_t zoneid, ip_stack_t *ipst) 244bd670b35SErik Nordmark { 245bd670b35SErik Nordmark return (ipif_lookup_addr_common_v6(addr, match_ill, 246bd670b35SErik Nordmark (IPIF_MATCH_ILLGRP | IPIF_MATCH_NONDUP), zoneid, 247bd670b35SErik Nordmark ipst)); 248e11c3f44Smeem } 249e11c3f44Smeem 250e11c3f44Smeem /* 251e11c3f44Smeem * Special abbreviated version of ipif_lookup_addr_v6() that doesn't match 252e11c3f44Smeem * `match_ill' across the IPMP group. This function is only needed in some 253e11c3f44Smeem * corner-cases; almost everything should use ipif_lookup_addr_v6(). 254e11c3f44Smeem */ 255e11c3f44Smeem ipif_t * 256e11c3f44Smeem ipif_lookup_addr_exact_v6(const in6_addr_t *addr, ill_t *match_ill, 257e11c3f44Smeem ip_stack_t *ipst) 258e11c3f44Smeem { 259e11c3f44Smeem ASSERT(match_ill != NULL); 260bd670b35SErik Nordmark return (ipif_lookup_addr_common_v6(addr, match_ill, 0, ALL_ZONES, 261bd670b35SErik Nordmark ipst)); 262e11c3f44Smeem } 263e11c3f44Smeem 264e11c3f44Smeem /* 2655597b60aSnordmark * Look for an ipif with the specified address. For point-point links 2665597b60aSnordmark * we look for matches on either the destination address and the local 2675597b60aSnordmark * address, but we ignore the check on the local address if IPIF_UNNUMBERED 2685597b60aSnordmark * is set. 269e11c3f44Smeem * If the `match_ill' argument is non-NULL, the lookup is restricted to that 270e11c3f44Smeem * ill (or illgrp if `match_ill' is in an IPMP group). 2715597b60aSnordmark * Return the zoneid for the ipif. ALL_ZONES if none found. 2725597b60aSnordmark */ 2735597b60aSnordmark zoneid_t 274f4b3ec61Sdh155122 ipif_lookup_addr_zoneid_v6(const in6_addr_t *addr, ill_t *match_ill, 275f4b3ec61Sdh155122 ip_stack_t *ipst) 2765597b60aSnordmark { 2775597b60aSnordmark ipif_t *ipif; 2785597b60aSnordmark ill_t *ill; 2795597b60aSnordmark boolean_t ptp = B_FALSE; 2805597b60aSnordmark ill_walk_context_t ctx; 2815597b60aSnordmark zoneid_t zoneid; 2825597b60aSnordmark 283f4b3ec61Sdh155122 rw_enter(&ipst->ips_ill_g_lock, RW_READER); 2845597b60aSnordmark /* 2855597b60aSnordmark * Repeat twice, first based on local addresses and 2865597b60aSnordmark * next time for pointopoint. 2875597b60aSnordmark */ 2885597b60aSnordmark repeat: 289f4b3ec61Sdh155122 ill = ILL_START_WALK_V6(&ctx, ipst); 2905597b60aSnordmark for (; ill != NULL; ill = ill_next(&ctx, ill)) { 291e11c3f44Smeem if (match_ill != NULL && ill != match_ill && 292e11c3f44Smeem !IS_IN_SAME_ILLGRP(ill, match_ill)) { 2935597b60aSnordmark continue; 2945597b60aSnordmark } 2955597b60aSnordmark mutex_enter(&ill->ill_lock); 2965597b60aSnordmark for (ipif = ill->ill_ipif; ipif != NULL; 2975597b60aSnordmark ipif = ipif->ipif_next) { 2985597b60aSnordmark /* Allow the ipif to be down */ 2995597b60aSnordmark if ((!ptp && (IN6_ARE_ADDR_EQUAL( 3005597b60aSnordmark &ipif->ipif_v6lcl_addr, addr) && 3015597b60aSnordmark (ipif->ipif_flags & IPIF_UNNUMBERED) == 0)) || 3025597b60aSnordmark (ptp && (ipif->ipif_flags & IPIF_POINTOPOINT) && 3035597b60aSnordmark IN6_ARE_ADDR_EQUAL(&ipif->ipif_v6pp_dst_addr, 3045597b60aSnordmark addr)) && 3055597b60aSnordmark !(ipif->ipif_state_flags & IPIF_CONDEMNED)) { 3065597b60aSnordmark zoneid = ipif->ipif_zoneid; 3075597b60aSnordmark mutex_exit(&ill->ill_lock); 308f4b3ec61Sdh155122 rw_exit(&ipst->ips_ill_g_lock); 3095597b60aSnordmark /* 3105597b60aSnordmark * If ipif_zoneid was ALL_ZONES then we have 3115597b60aSnordmark * a trusted extensions shared IP address. 3125597b60aSnordmark * In that case GLOBAL_ZONEID works to send. 3135597b60aSnordmark */ 3145597b60aSnordmark if (zoneid == ALL_ZONES) 3155597b60aSnordmark zoneid = GLOBAL_ZONEID; 3165597b60aSnordmark return (zoneid); 3175597b60aSnordmark } 3185597b60aSnordmark } 3195597b60aSnordmark mutex_exit(&ill->ill_lock); 3205597b60aSnordmark } 3215597b60aSnordmark 3225597b60aSnordmark /* If we already did the ptp case, then we are done */ 3235597b60aSnordmark if (ptp) { 324f4b3ec61Sdh155122 rw_exit(&ipst->ips_ill_g_lock); 3255597b60aSnordmark return (ALL_ZONES); 3265597b60aSnordmark } 3275597b60aSnordmark ptp = B_TRUE; 3285597b60aSnordmark goto repeat; 3295597b60aSnordmark } 3305597b60aSnordmark 3315597b60aSnordmark /* 3327c478bd9Sstevel@tonic-gate * Perform various checks to verify that an address would make sense as a local 3337c478bd9Sstevel@tonic-gate * interface address. This is currently only called when an attempt is made 3347c478bd9Sstevel@tonic-gate * to set a local address. 3357c478bd9Sstevel@tonic-gate * 3367c478bd9Sstevel@tonic-gate * Does not allow a v4-mapped address, an address that equals the subnet 3377c478bd9Sstevel@tonic-gate * anycast address, ... a multicast address, ... 3387c478bd9Sstevel@tonic-gate */ 3397c478bd9Sstevel@tonic-gate boolean_t 3407c478bd9Sstevel@tonic-gate ip_local_addr_ok_v6(const in6_addr_t *addr, const in6_addr_t *subnet_mask) 3417c478bd9Sstevel@tonic-gate { 3427c478bd9Sstevel@tonic-gate in6_addr_t subnet; 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(addr)) 3457c478bd9Sstevel@tonic-gate return (B_TRUE); /* Allow all zeros */ 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate /* 3487c478bd9Sstevel@tonic-gate * Don't allow all zeroes or host part, but allow 3497c478bd9Sstevel@tonic-gate * all ones netmask. 3507c478bd9Sstevel@tonic-gate */ 3517c478bd9Sstevel@tonic-gate V6_MASK_COPY(*addr, *subnet_mask, subnet); 3527c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(addr) || 3537c478bd9Sstevel@tonic-gate (IN6_ARE_ADDR_EQUAL(addr, &subnet) && 3547c478bd9Sstevel@tonic-gate !IN6_ARE_ADDR_EQUAL(subnet_mask, &ipv6_all_ones)) || 3557c478bd9Sstevel@tonic-gate (IN6_IS_ADDR_V4COMPAT(addr) && CLASSD(V4_PART_OF_V6((*addr)))) || 3567c478bd9Sstevel@tonic-gate IN6_IS_ADDR_MULTICAST(addr)) 3577c478bd9Sstevel@tonic-gate return (B_FALSE); 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate return (B_TRUE); 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate /* 3637c478bd9Sstevel@tonic-gate * Perform various checks to verify that an address would make sense as a 3647c478bd9Sstevel@tonic-gate * remote/subnet interface address. 3657c478bd9Sstevel@tonic-gate */ 3667c478bd9Sstevel@tonic-gate boolean_t 3677c478bd9Sstevel@tonic-gate ip_remote_addr_ok_v6(const in6_addr_t *addr, const in6_addr_t *subnet_mask) 3687c478bd9Sstevel@tonic-gate { 3697c478bd9Sstevel@tonic-gate in6_addr_t subnet; 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(addr)) 3727c478bd9Sstevel@tonic-gate return (B_TRUE); /* Allow all zeros */ 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate V6_MASK_COPY(*addr, *subnet_mask, subnet); 3757c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(addr) || 3767c478bd9Sstevel@tonic-gate (IN6_ARE_ADDR_EQUAL(addr, &subnet) && 3777c478bd9Sstevel@tonic-gate !IN6_ARE_ADDR_EQUAL(subnet_mask, &ipv6_all_ones)) || 3787c478bd9Sstevel@tonic-gate IN6_IS_ADDR_MULTICAST(addr) || 3797c478bd9Sstevel@tonic-gate (IN6_IS_ADDR_V4COMPAT(addr) && CLASSD(V4_PART_OF_V6((*addr))))) 3807c478bd9Sstevel@tonic-gate return (B_FALSE); 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate return (B_TRUE); 3837c478bd9Sstevel@tonic-gate } 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate /* 3867c478bd9Sstevel@tonic-gate * ip_rt_add_v6 is called to add an IPv6 route to the forwarding table. 387bd670b35SErik Nordmark * ill is passed in to associate it with the correct interface 3887c478bd9Sstevel@tonic-gate * (for link-local destinations and gateways). 389bd670b35SErik Nordmark * If ire_arg is set, then we return the held IRE in that location. 3907c478bd9Sstevel@tonic-gate */ 3917c478bd9Sstevel@tonic-gate /* ARGSUSED1 */ 3927c478bd9Sstevel@tonic-gate int 3937c478bd9Sstevel@tonic-gate ip_rt_add_v6(const in6_addr_t *dst_addr, const in6_addr_t *mask, 3947c478bd9Sstevel@tonic-gate const in6_addr_t *gw_addr, const in6_addr_t *src_addr, int flags, 395bd670b35SErik Nordmark ill_t *ill, ire_t **ire_arg, struct rtsa_s *sp, ip_stack_t *ipst, 396bd670b35SErik Nordmark zoneid_t zoneid) 3977c478bd9Sstevel@tonic-gate { 398bd670b35SErik Nordmark ire_t *ire, *nire; 3997c478bd9Sstevel@tonic-gate ire_t *gw_ire = NULL; 4007c478bd9Sstevel@tonic-gate ipif_t *ipif; 4017c478bd9Sstevel@tonic-gate uint_t type; 4027c478bd9Sstevel@tonic-gate int match_flags = MATCH_IRE_TYPE; 40345916cd2Sjpk tsol_gc_t *gc = NULL; 40445916cd2Sjpk tsol_gcgrp_t *gcgrp = NULL; 40545916cd2Sjpk boolean_t gcgrp_xtraref = B_FALSE; 40644b099c4SSowmini Varadhan boolean_t unbound = B_FALSE; 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate if (ire_arg != NULL) 4097c478bd9Sstevel@tonic-gate *ire_arg = NULL; 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate /* 4127c478bd9Sstevel@tonic-gate * Prevent routes with a zero gateway from being created (since 4137c478bd9Sstevel@tonic-gate * interfaces can currently be plumbed and brought up with no assigned 4147c478bd9Sstevel@tonic-gate * address). 4157c478bd9Sstevel@tonic-gate */ 4167c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(gw_addr)) 4177c478bd9Sstevel@tonic-gate return (ENETUNREACH); 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate /* 4207c478bd9Sstevel@tonic-gate * If this is the case of RTF_HOST being set, then we set the netmask 4217c478bd9Sstevel@tonic-gate * to all ones (regardless if one was supplied). 4227c478bd9Sstevel@tonic-gate */ 4237c478bd9Sstevel@tonic-gate if (flags & RTF_HOST) 4247c478bd9Sstevel@tonic-gate mask = &ipv6_all_ones; 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate /* 4277c478bd9Sstevel@tonic-gate * Get the ipif, if any, corresponding to the gw_addr 428bd670b35SErik Nordmark * If -ifp was specified we restrict ourselves to the ill, otherwise 429bd670b35SErik Nordmark * we match on the gatway and destination to handle unnumbered pt-pt 430bd670b35SErik Nordmark * interfaces. 4317c478bd9Sstevel@tonic-gate */ 432bd670b35SErik Nordmark if (ill != NULL) 433bd670b35SErik Nordmark ipif = ipif_lookup_addr_v6(gw_addr, ill, ALL_ZONES, ipst); 434bd670b35SErik Nordmark else 435bd670b35SErik Nordmark ipif = ipif_lookup_interface_v6(gw_addr, dst_addr, ipst); 436bd670b35SErik Nordmark if (ipif != NULL) { 437bd670b35SErik Nordmark if (IS_VNI(ipif->ipif_ill)) { 438bd670b35SErik Nordmark ipif_refrele(ipif); 439bd670b35SErik Nordmark return (EINVAL); 440bd670b35SErik Nordmark } 4417c478bd9Sstevel@tonic-gate } 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate /* 4447c478bd9Sstevel@tonic-gate * GateD will attempt to create routes with a loopback interface 4457c478bd9Sstevel@tonic-gate * address as the gateway and with RTF_GATEWAY set. We allow 4467c478bd9Sstevel@tonic-gate * these routes to be added, but create them as interface routes 4477c478bd9Sstevel@tonic-gate * since the gateway is an interface address. 4487c478bd9Sstevel@tonic-gate */ 449d21e5363Srk129064 if ((ipif != NULL) && (ipif->ipif_ire_type == IRE_LOOPBACK)) { 4507c478bd9Sstevel@tonic-gate flags &= ~RTF_GATEWAY; 451d21e5363Srk129064 if (IN6_ARE_ADDR_EQUAL(gw_addr, &ipv6_loopback) && 452d21e5363Srk129064 IN6_ARE_ADDR_EQUAL(dst_addr, &ipv6_loopback) && 453d21e5363Srk129064 IN6_ARE_ADDR_EQUAL(mask, &ipv6_all_ones)) { 454bd670b35SErik Nordmark ire = ire_ftable_lookup_v6(dst_addr, 0, 0, IRE_LOOPBACK, 455bd670b35SErik Nordmark NULL, ALL_ZONES, NULL, MATCH_IRE_TYPE, 0, ipst, 456bd670b35SErik Nordmark NULL); 457d21e5363Srk129064 if (ire != NULL) { 458d21e5363Srk129064 ire_refrele(ire); 459d21e5363Srk129064 ipif_refrele(ipif); 460d21e5363Srk129064 return (EEXIST); 461d21e5363Srk129064 } 462bd670b35SErik Nordmark ip1dbg(("ip_rt_add_v6: 0x%p creating IRE 0x%x" 463d21e5363Srk129064 "for 0x%x\n", (void *)ipif, 464d21e5363Srk129064 ipif->ipif_ire_type, 465d21e5363Srk129064 ntohl(ipif->ipif_lcl_addr))); 466d21e5363Srk129064 ire = ire_create_v6( 467d21e5363Srk129064 dst_addr, 468d21e5363Srk129064 mask, 469d21e5363Srk129064 NULL, 470bd670b35SErik Nordmark ipif->ipif_ire_type, /* LOOPBACK */ 471bd670b35SErik Nordmark ipif->ipif_ill, 472bd670b35SErik Nordmark zoneid, 473bd670b35SErik Nordmark (ipif->ipif_flags & IPIF_PRIVATE) ? RTF_PRIVATE : 0, 474f4b3ec61Sdh155122 NULL, 475f4b3ec61Sdh155122 ipst); 476bd670b35SErik Nordmark 477d21e5363Srk129064 if (ire == NULL) { 478d21e5363Srk129064 ipif_refrele(ipif); 479d21e5363Srk129064 return (ENOMEM); 480d21e5363Srk129064 } 481bd670b35SErik Nordmark /* src address assigned by the caller? */ 482bd670b35SErik Nordmark if ((flags & RTF_SETSRC) && 483bd670b35SErik Nordmark !IN6_IS_ADDR_UNSPECIFIED(src_addr)) 484bd670b35SErik Nordmark ire->ire_setsrc_addr_v6 = *src_addr; 485bd670b35SErik Nordmark 486bd670b35SErik Nordmark nire = ire_add(ire); 487bd670b35SErik Nordmark if (nire == NULL) { 488d21e5363Srk129064 /* 489bd670b35SErik Nordmark * In the result of failure, ire_add() will have 490bd670b35SErik Nordmark * already deleted the ire in question, so there 491bd670b35SErik Nordmark * is no need to do that here. 492d21e5363Srk129064 */ 493d21e5363Srk129064 ipif_refrele(ipif); 494bd670b35SErik Nordmark return (ENOMEM); 495bd670b35SErik Nordmark } 496bd670b35SErik Nordmark /* 497bd670b35SErik Nordmark * Check if it was a duplicate entry. This handles 498bd670b35SErik Nordmark * the case of two racing route adds for the same route 499bd670b35SErik Nordmark */ 500bd670b35SErik Nordmark if (nire != ire) { 501bd670b35SErik Nordmark ASSERT(nire->ire_identical_ref > 1); 502bd670b35SErik Nordmark ire_delete(nire); 503bd670b35SErik Nordmark ire_refrele(nire); 504bd670b35SErik Nordmark ipif_refrele(ipif); 505bd670b35SErik Nordmark return (EEXIST); 506bd670b35SErik Nordmark } 507bd670b35SErik Nordmark ire = nire; 508bd670b35SErik Nordmark goto save_ire; 509d21e5363Srk129064 } 510d21e5363Srk129064 } 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate /* 513bd670b35SErik Nordmark * The routes for multicast with CGTP are quite special in that 514bd670b35SErik Nordmark * the gateway is the local interface address, yet RTF_GATEWAY 515bd670b35SErik Nordmark * is set. We turn off RTF_GATEWAY to provide compatibility with 516bd670b35SErik Nordmark * this undocumented and unusual use of multicast routes. 517bd670b35SErik Nordmark */ 518bd670b35SErik Nordmark if ((flags & RTF_MULTIRT) && ipif != NULL) 519bd670b35SErik Nordmark flags &= ~RTF_GATEWAY; 520bd670b35SErik Nordmark 521bd670b35SErik Nordmark /* 5227c478bd9Sstevel@tonic-gate * Traditionally, interface routes are ones where RTF_GATEWAY isn't set 5237c478bd9Sstevel@tonic-gate * and the gateway address provided is one of the system's interface 5247c478bd9Sstevel@tonic-gate * addresses. By using the routing socket interface and supplying an 5257c478bd9Sstevel@tonic-gate * RTA_IFP sockaddr with an interface index, an alternate method of 5267c478bd9Sstevel@tonic-gate * specifying an interface route to be created is available which uses 5277c478bd9Sstevel@tonic-gate * the interface index that specifies the outgoing interface rather than 5287c478bd9Sstevel@tonic-gate * the address of an outgoing interface (which may not be able to 5297c478bd9Sstevel@tonic-gate * uniquely identify an interface). When coupled with the RTF_GATEWAY 5307c478bd9Sstevel@tonic-gate * flag, routes can be specified which not only specify the next-hop to 5317c478bd9Sstevel@tonic-gate * be used when routing to a certain prefix, but also which outgoing 5327c478bd9Sstevel@tonic-gate * interface should be used. 5337c478bd9Sstevel@tonic-gate * 5347c478bd9Sstevel@tonic-gate * Previously, interfaces would have unique addresses assigned to them 5357c478bd9Sstevel@tonic-gate * and so the address assigned to a particular interface could be used 5367c478bd9Sstevel@tonic-gate * to identify a particular interface. One exception to this was the 5377c478bd9Sstevel@tonic-gate * case of an unnumbered interface (where IPIF_UNNUMBERED was set). 5387c478bd9Sstevel@tonic-gate * 5397c478bd9Sstevel@tonic-gate * With the advent of IPv6 and its link-local addresses, this 5407c478bd9Sstevel@tonic-gate * restriction was relaxed and interfaces could share addresses between 5417c478bd9Sstevel@tonic-gate * themselves. In fact, typically all of the link-local interfaces on 5427c478bd9Sstevel@tonic-gate * an IPv6 node or router will have the same link-local address. In 5437c478bd9Sstevel@tonic-gate * order to differentiate between these interfaces, the use of an 5447c478bd9Sstevel@tonic-gate * interface index is necessary and this index can be carried inside a 5457c478bd9Sstevel@tonic-gate * RTA_IFP sockaddr (which is actually a sockaddr_dl). One restriction 5467c478bd9Sstevel@tonic-gate * of using the interface index, however, is that all of the ipif's that 5477c478bd9Sstevel@tonic-gate * are part of an ill have the same index and so the RTA_IFP sockaddr 5487c478bd9Sstevel@tonic-gate * cannot be used to differentiate between ipif's (or logical 5497c478bd9Sstevel@tonic-gate * interfaces) that belong to the same ill (physical interface). 5507c478bd9Sstevel@tonic-gate * 5517c478bd9Sstevel@tonic-gate * For example, in the following case involving IPv4 interfaces and 5527c478bd9Sstevel@tonic-gate * logical interfaces 5537c478bd9Sstevel@tonic-gate * 5547c478bd9Sstevel@tonic-gate * 192.0.2.32 255.255.255.224 192.0.2.33 U if0 555bd670b35SErik Nordmark * 192.0.2.32 255.255.255.224 192.0.2.34 U if0 556bd670b35SErik Nordmark * 192.0.2.32 255.255.255.224 192.0.2.35 U if0 5577c478bd9Sstevel@tonic-gate * 5587c478bd9Sstevel@tonic-gate * the ipif's corresponding to each of these interface routes can be 5597c478bd9Sstevel@tonic-gate * uniquely identified by the "gateway" (actually interface address). 5607c478bd9Sstevel@tonic-gate * 5617c478bd9Sstevel@tonic-gate * In this case involving multiple IPv6 default routes to a particular 5627c478bd9Sstevel@tonic-gate * link-local gateway, the use of RTA_IFP is necessary to specify which 5637c478bd9Sstevel@tonic-gate * default route is of interest: 5647c478bd9Sstevel@tonic-gate * 5657c478bd9Sstevel@tonic-gate * default fe80::123:4567:89ab:cdef U if0 5667c478bd9Sstevel@tonic-gate * default fe80::123:4567:89ab:cdef U if1 5677c478bd9Sstevel@tonic-gate */ 5687c478bd9Sstevel@tonic-gate 5697c478bd9Sstevel@tonic-gate /* RTF_GATEWAY not set */ 5707c478bd9Sstevel@tonic-gate if (!(flags & RTF_GATEWAY)) { 57145916cd2Sjpk if (sp != NULL) { 57245916cd2Sjpk ip2dbg(("ip_rt_add_v6: gateway security attributes " 57345916cd2Sjpk "cannot be set with interface route\n")); 574bd670b35SErik Nordmark if (ipif != NULL) 57545916cd2Sjpk ipif_refrele(ipif); 57645916cd2Sjpk return (EINVAL); 57745916cd2Sjpk } 57845916cd2Sjpk 5797c478bd9Sstevel@tonic-gate /* 580bd670b35SErik Nordmark * Whether or not ill (RTA_IFP) is set, we require that 581bd670b35SErik Nordmark * the gateway is one of our local addresses. 5827c478bd9Sstevel@tonic-gate */ 5837c478bd9Sstevel@tonic-gate if (ipif == NULL) 5847c478bd9Sstevel@tonic-gate return (ENETUNREACH); 585bd670b35SErik Nordmark 586bd670b35SErik Nordmark /* 587bd670b35SErik Nordmark * We use MATCH_IRE_ILL here. If the caller specified an 588bd670b35SErik Nordmark * interface (from the RTA_IFP sockaddr) we use it, otherwise 589bd670b35SErik Nordmark * we use the ill derived from the gateway address. 590bd670b35SErik Nordmark * We can always match the gateway address since we record it 591bd670b35SErik Nordmark * in ire_gateway_addr. 592bd670b35SErik Nordmark * We don't allow RTA_IFP to specify a different ill than the 593bd670b35SErik Nordmark * one matching the ipif to make sure we can delete the route. 594bd670b35SErik Nordmark */ 595bd670b35SErik Nordmark match_flags |= MATCH_IRE_GW | MATCH_IRE_ILL; 596bd670b35SErik Nordmark if (ill == NULL) { 597bd670b35SErik Nordmark ill = ipif->ipif_ill; 598bd670b35SErik Nordmark } else if (ill != ipif->ipif_ill) { 599bd670b35SErik Nordmark ipif_refrele(ipif); 600bd670b35SErik Nordmark return (EINVAL); 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate /* 6047c478bd9Sstevel@tonic-gate * We check for an existing entry at this point. 6057c478bd9Sstevel@tonic-gate */ 6067c478bd9Sstevel@tonic-gate match_flags |= MATCH_IRE_MASK; 607bd670b35SErik Nordmark ire = ire_ftable_lookup_v6(dst_addr, mask, gw_addr, 608bd670b35SErik Nordmark IRE_INTERFACE, ill, ALL_ZONES, NULL, match_flags, 0, ipst, 609bd670b35SErik Nordmark NULL); 6107c478bd9Sstevel@tonic-gate if (ire != NULL) { 6117c478bd9Sstevel@tonic-gate ire_refrele(ire); 6127c478bd9Sstevel@tonic-gate ipif_refrele(ipif); 6137c478bd9Sstevel@tonic-gate return (EEXIST); 6147c478bd9Sstevel@tonic-gate } 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate /* 617c57e370fSErik Nordmark * Some software (for example, GateD and Sun Cluster) attempts 618c57e370fSErik Nordmark * to create (what amount to) IRE_PREFIX routes with the 619c57e370fSErik Nordmark * loopback address as the gateway. This is primarily done to 620c57e370fSErik Nordmark * set up prefixes with the RTF_REJECT flag set (for example, 621c57e370fSErik Nordmark * when generating aggregate routes). We also OR in the 622c57e370fSErik Nordmark * RTF_BLACKHOLE flag as these interface routes, by 623c57e370fSErik Nordmark * definition, can only be that. 624c57e370fSErik Nordmark * 625c57e370fSErik Nordmark * If the IRE type (as defined by ill->ill_net_type) would be 626c57e370fSErik Nordmark * IRE_LOOPBACK, then we map the request into a 627c57e370fSErik Nordmark * IRE_IF_NORESOLVER. 628c57e370fSErik Nordmark * 629c57e370fSErik Nordmark * Needless to say, the real IRE_LOOPBACK is NOT created by this 630c57e370fSErik Nordmark * routine, but rather using ire_create_v6() directly. 631c57e370fSErik Nordmark */ 632c57e370fSErik Nordmark type = ill->ill_net_type; 633c57e370fSErik Nordmark if (type == IRE_LOOPBACK) { 634c57e370fSErik Nordmark type = IRE_IF_NORESOLVER; 635c57e370fSErik Nordmark flags |= RTF_BLACKHOLE; 636c57e370fSErik Nordmark } 637c57e370fSErik Nordmark 638c57e370fSErik Nordmark /* 639c57e370fSErik Nordmark * Create a copy of the IRE_IF_NORESOLVER or 640bd670b35SErik Nordmark * IRE_IF_RESOLVER with the modified address, netmask, and 641bd670b35SErik Nordmark * gateway. 6427c478bd9Sstevel@tonic-gate */ 6437c478bd9Sstevel@tonic-gate ire = ire_create_v6( 6447c478bd9Sstevel@tonic-gate dst_addr, 6457c478bd9Sstevel@tonic-gate mask, 646bd670b35SErik Nordmark gw_addr, 647c57e370fSErik Nordmark type, 648bd670b35SErik Nordmark ill, 649bd670b35SErik Nordmark zoneid, 6507c478bd9Sstevel@tonic-gate flags, 651f4b3ec61Sdh155122 NULL, 652f4b3ec61Sdh155122 ipst); 6537c478bd9Sstevel@tonic-gate if (ire == NULL) { 6547c478bd9Sstevel@tonic-gate ipif_refrele(ipif); 6557c478bd9Sstevel@tonic-gate return (ENOMEM); 6567c478bd9Sstevel@tonic-gate } 6577c478bd9Sstevel@tonic-gate 658bd670b35SErik Nordmark /* src address assigned by the caller? */ 659bd670b35SErik Nordmark if ((flags & RTF_SETSRC) && !IN6_IS_ADDR_UNSPECIFIED(src_addr)) 660bd670b35SErik Nordmark ire->ire_setsrc_addr_v6 = *src_addr; 661bd670b35SErik Nordmark 662bd670b35SErik Nordmark nire = ire_add(ire); 663bd670b35SErik Nordmark if (nire == NULL) { 6647c478bd9Sstevel@tonic-gate /* 665bd670b35SErik Nordmark * In the result of failure, ire_add() will have 666bd670b35SErik Nordmark * already deleted the ire in question, so there 667bd670b35SErik Nordmark * is no need to do that here. 6687c478bd9Sstevel@tonic-gate */ 6697c478bd9Sstevel@tonic-gate ipif_refrele(ipif); 670bd670b35SErik Nordmark return (ENOMEM); 6717c478bd9Sstevel@tonic-gate } 672bd670b35SErik Nordmark /* 673bd670b35SErik Nordmark * Check if it was a duplicate entry. This handles 674bd670b35SErik Nordmark * the case of two racing route adds for the same route 675bd670b35SErik Nordmark */ 676bd670b35SErik Nordmark if (nire != ire) { 677bd670b35SErik Nordmark ASSERT(nire->ire_identical_ref > 1); 678bd670b35SErik Nordmark ire_delete(nire); 679bd670b35SErik Nordmark ire_refrele(nire); 6807c478bd9Sstevel@tonic-gate ipif_refrele(ipif); 681bd670b35SErik Nordmark return (EEXIST); 682bd670b35SErik Nordmark } 683bd670b35SErik Nordmark ire = nire; 684bd670b35SErik Nordmark goto save_ire; 6857c478bd9Sstevel@tonic-gate } 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate /* 6887c478bd9Sstevel@tonic-gate * Get an interface IRE for the specified gateway. 6897c478bd9Sstevel@tonic-gate * If we don't have an IRE_IF_NORESOLVER or IRE_IF_RESOLVER for the 6907c478bd9Sstevel@tonic-gate * gateway, it is currently unreachable and we fail the request 691b1b66e09SErik Nordmark * accordingly. We reject any RTF_GATEWAY routes where the gateway 692b1b66e09SErik Nordmark * is an IRE_LOCAL or IRE_LOOPBACK. 693bd670b35SErik Nordmark * If RTA_IFP was specified we look on that particular ill. 6947c478bd9Sstevel@tonic-gate */ 695bd670b35SErik Nordmark if (ill != NULL) 6967c478bd9Sstevel@tonic-gate match_flags |= MATCH_IRE_ILL; 697bd670b35SErik Nordmark 698bd670b35SErik Nordmark /* Check whether the gateway is reachable. */ 699b1b66e09SErik Nordmark again: 700b1b66e09SErik Nordmark type = IRE_INTERFACE | IRE_LOCAL | IRE_LOOPBACK; 701bd670b35SErik Nordmark if (flags & RTF_INDIRECT) 702bd670b35SErik Nordmark type |= IRE_OFFLINK; 703bd670b35SErik Nordmark 704bd670b35SErik Nordmark gw_ire = ire_ftable_lookup_v6(gw_addr, 0, 0, type, ill, 705bd670b35SErik Nordmark ALL_ZONES, NULL, match_flags, 0, ipst, NULL); 706bd670b35SErik Nordmark if (gw_ire == NULL) { 707b1b66e09SErik Nordmark /* 708b1b66e09SErik Nordmark * With IPMP, we allow host routes to influence in.mpathd's 709b1b66e09SErik Nordmark * target selection. However, if the test addresses are on 710b1b66e09SErik Nordmark * their own network, the above lookup will fail since the 711b1b66e09SErik Nordmark * underlying IRE_INTERFACEs are marked hidden. So allow 712b1b66e09SErik Nordmark * hidden test IREs to be found and try again. 713b1b66e09SErik Nordmark */ 714b1b66e09SErik Nordmark if (!(match_flags & MATCH_IRE_TESTHIDDEN)) { 715b1b66e09SErik Nordmark match_flags |= MATCH_IRE_TESTHIDDEN; 716b1b66e09SErik Nordmark goto again; 717b1b66e09SErik Nordmark } 718b1b66e09SErik Nordmark if (ipif != NULL) 719b1b66e09SErik Nordmark ipif_refrele(ipif); 720b1b66e09SErik Nordmark return (ENETUNREACH); 721b1b66e09SErik Nordmark } 722b1b66e09SErik Nordmark if (gw_ire->ire_type & (IRE_LOCAL|IRE_LOOPBACK)) { 723b1b66e09SErik Nordmark ire_refrele(gw_ire); 724bd670b35SErik Nordmark if (ipif != NULL) 725bd670b35SErik Nordmark ipif_refrele(ipif); 7267c478bd9Sstevel@tonic-gate return (ENETUNREACH); 727bd670b35SErik Nordmark } 72844b099c4SSowmini Varadhan if (ill == NULL && !(flags & RTF_INDIRECT)) { 72944b099c4SSowmini Varadhan unbound = B_TRUE; 73044b099c4SSowmini Varadhan if (ipst->ips_ipv6_strict_src_multihoming > 0) 73144b099c4SSowmini Varadhan ill = gw_ire->ire_ill; 73244b099c4SSowmini Varadhan } 7337c478bd9Sstevel@tonic-gate 7347c478bd9Sstevel@tonic-gate /* 7357c478bd9Sstevel@tonic-gate * We create one of three types of IREs as a result of this request 7367c478bd9Sstevel@tonic-gate * based on the netmask. A netmask of all ones (which is automatically 7377c478bd9Sstevel@tonic-gate * assumed when RTF_HOST is set) results in an IRE_HOST being created. 7387c478bd9Sstevel@tonic-gate * An all zeroes netmask implies a default route so an IRE_DEFAULT is 7397c478bd9Sstevel@tonic-gate * created. Otherwise, an IRE_PREFIX route is created for the 7407c478bd9Sstevel@tonic-gate * destination prefix. 7417c478bd9Sstevel@tonic-gate */ 7427c478bd9Sstevel@tonic-gate if (IN6_ARE_ADDR_EQUAL(mask, &ipv6_all_ones)) 7437c478bd9Sstevel@tonic-gate type = IRE_HOST; 7447c478bd9Sstevel@tonic-gate else if (IN6_IS_ADDR_UNSPECIFIED(mask)) 7457c478bd9Sstevel@tonic-gate type = IRE_DEFAULT; 7467c478bd9Sstevel@tonic-gate else 7477c478bd9Sstevel@tonic-gate type = IRE_PREFIX; 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate /* check for a duplicate entry */ 750bd670b35SErik Nordmark ire = ire_ftable_lookup_v6(dst_addr, mask, gw_addr, type, ill, 751bd670b35SErik Nordmark ALL_ZONES, NULL, 752bd670b35SErik Nordmark match_flags | MATCH_IRE_MASK | MATCH_IRE_GW, 0, ipst, NULL); 7537c478bd9Sstevel@tonic-gate if (ire != NULL) { 754bd670b35SErik Nordmark if (ipif != NULL) 755bd670b35SErik Nordmark ipif_refrele(ipif); 7567c478bd9Sstevel@tonic-gate ire_refrele(gw_ire); 7577c478bd9Sstevel@tonic-gate ire_refrele(ire); 7587c478bd9Sstevel@tonic-gate return (EEXIST); 7597c478bd9Sstevel@tonic-gate } 7607c478bd9Sstevel@tonic-gate 76145916cd2Sjpk /* Security attribute exists */ 76245916cd2Sjpk if (sp != NULL) { 76345916cd2Sjpk tsol_gcgrp_addr_t ga; 76445916cd2Sjpk 76545916cd2Sjpk /* find or create the gateway credentials group */ 76645916cd2Sjpk ga.ga_af = AF_INET6; 76745916cd2Sjpk ga.ga_addr = *gw_addr; 76845916cd2Sjpk 76945916cd2Sjpk /* we hold reference to it upon success */ 77045916cd2Sjpk gcgrp = gcgrp_lookup(&ga, B_TRUE); 77145916cd2Sjpk if (gcgrp == NULL) { 772bd670b35SErik Nordmark if (ipif != NULL) 773bd670b35SErik Nordmark ipif_refrele(ipif); 77445916cd2Sjpk ire_refrele(gw_ire); 77545916cd2Sjpk return (ENOMEM); 77645916cd2Sjpk } 77745916cd2Sjpk 77845916cd2Sjpk /* 77945916cd2Sjpk * Create and add the security attribute to the group; a 78045916cd2Sjpk * reference to the group is made upon allocating a new 78145916cd2Sjpk * entry successfully. If it finds an already-existing 78245916cd2Sjpk * entry for the security attribute in the group, it simply 78345916cd2Sjpk * returns it and no new reference is made to the group. 78445916cd2Sjpk */ 78545916cd2Sjpk gc = gc_create(sp, gcgrp, &gcgrp_xtraref); 78645916cd2Sjpk if (gc == NULL) { 78745916cd2Sjpk /* release reference held by gcgrp_lookup */ 78845916cd2Sjpk GCGRP_REFRELE(gcgrp); 789bd670b35SErik Nordmark if (ipif != NULL) 790bd670b35SErik Nordmark ipif_refrele(ipif); 79145916cd2Sjpk ire_refrele(gw_ire); 79245916cd2Sjpk return (ENOMEM); 79345916cd2Sjpk } 79445916cd2Sjpk } 79545916cd2Sjpk 7967c478bd9Sstevel@tonic-gate /* Create the IRE. */ 7977c478bd9Sstevel@tonic-gate ire = ire_create_v6( 7987c478bd9Sstevel@tonic-gate dst_addr, /* dest address */ 7997c478bd9Sstevel@tonic-gate mask, /* mask */ 8007c478bd9Sstevel@tonic-gate gw_addr, /* gateway address */ 8017c478bd9Sstevel@tonic-gate (ushort_t)type, /* IRE type */ 802bd670b35SErik Nordmark ill, 803bd670b35SErik Nordmark zoneid, 8047c478bd9Sstevel@tonic-gate flags, 80545916cd2Sjpk gc, /* security attribute */ 806f4b3ec61Sdh155122 ipst); 807f4b3ec61Sdh155122 80845916cd2Sjpk /* 80945916cd2Sjpk * The ire holds a reference to the 'gc' and the 'gc' holds a 81045916cd2Sjpk * reference to the 'gcgrp'. We can now release the extra reference 81145916cd2Sjpk * the 'gcgrp' acquired in the gcgrp_lookup, if it was not used. 81245916cd2Sjpk */ 81345916cd2Sjpk if (gcgrp_xtraref) 81445916cd2Sjpk GCGRP_REFRELE(gcgrp); 8157c478bd9Sstevel@tonic-gate if (ire == NULL) { 81645916cd2Sjpk if (gc != NULL) 81745916cd2Sjpk GC_REFRELE(gc); 818bd670b35SErik Nordmark if (ipif != NULL) 819bd670b35SErik Nordmark ipif_refrele(ipif); 8207c478bd9Sstevel@tonic-gate ire_refrele(gw_ire); 8217c478bd9Sstevel@tonic-gate return (ENOMEM); 8227c478bd9Sstevel@tonic-gate } 8237c478bd9Sstevel@tonic-gate 824bd670b35SErik Nordmark /* src address assigned by the caller? */ 825bd670b35SErik Nordmark if ((flags & RTF_SETSRC) && !IN6_IS_ADDR_UNSPECIFIED(src_addr)) 826bd670b35SErik Nordmark ire->ire_setsrc_addr_v6 = *src_addr; 827bd670b35SErik Nordmark 82844b099c4SSowmini Varadhan ire->ire_unbound = unbound; 82944b099c4SSowmini Varadhan 8307c478bd9Sstevel@tonic-gate /* 8317c478bd9Sstevel@tonic-gate * POLICY: should we allow an RTF_HOST with address INADDR_ANY? 8327c478bd9Sstevel@tonic-gate * SUN/OS socket stuff does but do we really want to allow ::0 ? 8337c478bd9Sstevel@tonic-gate */ 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate /* Add the new IRE. */ 836bd670b35SErik Nordmark nire = ire_add(ire); 837bd670b35SErik Nordmark if (nire == NULL) { 8387c478bd9Sstevel@tonic-gate /* 839bd670b35SErik Nordmark * In the result of failure, ire_add() will have 840bd670b35SErik Nordmark * already deleted the ire in question, so there 841bd670b35SErik Nordmark * is no need to do that here. 8427c478bd9Sstevel@tonic-gate */ 843bd670b35SErik Nordmark if (ipif != NULL) 844bd670b35SErik Nordmark ipif_refrele(ipif); 8457c478bd9Sstevel@tonic-gate ire_refrele(gw_ire); 846bd670b35SErik Nordmark return (ENOMEM); 8477c478bd9Sstevel@tonic-gate } 848bd670b35SErik Nordmark /* 849bd670b35SErik Nordmark * Check if it was a duplicate entry. This handles 850bd670b35SErik Nordmark * the case of two racing route adds for the same route 851bd670b35SErik Nordmark */ 852bd670b35SErik Nordmark if (nire != ire) { 853bd670b35SErik Nordmark ASSERT(nire->ire_identical_ref > 1); 854bd670b35SErik Nordmark ire_delete(nire); 855bd670b35SErik Nordmark ire_refrele(nire); 856bd670b35SErik Nordmark if (ipif != NULL) 857bd670b35SErik Nordmark ipif_refrele(ipif); 858bd670b35SErik Nordmark ire_refrele(gw_ire); 859bd670b35SErik Nordmark return (EEXIST); 860bd670b35SErik Nordmark } 861bd670b35SErik Nordmark ire = nire; 8627c478bd9Sstevel@tonic-gate 8637c478bd9Sstevel@tonic-gate if (flags & RTF_MULTIRT) { 8647c478bd9Sstevel@tonic-gate /* 8657c478bd9Sstevel@tonic-gate * Invoke the CGTP (multirouting) filtering module 8667c478bd9Sstevel@tonic-gate * to add the dst address in the filtering database. 8677c478bd9Sstevel@tonic-gate * Replicated inbound packets coming from that address 8687c478bd9Sstevel@tonic-gate * will be filtered to discard the duplicates. 8697c478bd9Sstevel@tonic-gate * It is not necessary to call the CGTP filter hook 8707c478bd9Sstevel@tonic-gate * when the dst address is a multicast, because an 8717c478bd9Sstevel@tonic-gate * IP source address cannot be a multicast. 8727c478bd9Sstevel@tonic-gate */ 873655a42e2Snordmark if (ipst->ips_ip_cgtp_filter_ops != NULL && 8747c478bd9Sstevel@tonic-gate !IN6_IS_ADDR_MULTICAST(&(ire->ire_addr_v6))) { 875655a42e2Snordmark int res; 876bd670b35SErik Nordmark ipif_t *src_ipif; 877655a42e2Snordmark 878bd670b35SErik Nordmark /* Find the source address corresponding to gw_ire */ 879bd670b35SErik Nordmark src_ipif = ipif_lookup_addr_v6( 880bd670b35SErik Nordmark &gw_ire->ire_gateway_addr_v6, NULL, zoneid, ipst); 881bd670b35SErik Nordmark if (src_ipif != NULL) { 882bd670b35SErik Nordmark res = ipst->ips_ip_cgtp_filter_ops-> 883bd670b35SErik Nordmark cfo_add_dest_v6( 884655a42e2Snordmark ipst->ips_netstack->netstack_stackid, 8857c478bd9Sstevel@tonic-gate &ire->ire_addr_v6, 8867c478bd9Sstevel@tonic-gate &ire->ire_gateway_addr_v6, 887bd670b35SErik Nordmark &ire->ire_setsrc_addr_v6, 888bd670b35SErik Nordmark &src_ipif->ipif_v6lcl_addr); 889bd670b35SErik Nordmark ipif_refrele(src_ipif); 890bd670b35SErik Nordmark } else { 891bd670b35SErik Nordmark res = EADDRNOTAVAIL; 892bd670b35SErik Nordmark } 8937c478bd9Sstevel@tonic-gate if (res != 0) { 894bd670b35SErik Nordmark if (ipif != NULL) 895bd670b35SErik Nordmark ipif_refrele(ipif); 8967c478bd9Sstevel@tonic-gate ire_refrele(gw_ire); 8977c478bd9Sstevel@tonic-gate ire_delete(ire); 898bd670b35SErik Nordmark ire_refrele(ire); /* Held in ire_add */ 8997c478bd9Sstevel@tonic-gate return (res); 9007c478bd9Sstevel@tonic-gate } 9017c478bd9Sstevel@tonic-gate } 9027c478bd9Sstevel@tonic-gate } 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate save_ire: 9057c478bd9Sstevel@tonic-gate if (gw_ire != NULL) { 9067c478bd9Sstevel@tonic-gate ire_refrele(gw_ire); 907bd670b35SErik Nordmark gw_ire = NULL; 9087c478bd9Sstevel@tonic-gate } 909bd670b35SErik Nordmark if (ire->ire_ill != NULL) { 9107c478bd9Sstevel@tonic-gate /* 9117c478bd9Sstevel@tonic-gate * Save enough information so that we can recreate the IRE if 912bd670b35SErik Nordmark * the ILL goes down and then up. The metrics associated 9137c478bd9Sstevel@tonic-gate * with the route will be saved as well when rts_setmetrics() is 9147c478bd9Sstevel@tonic-gate * called after the IRE has been created. In the case where 9157c478bd9Sstevel@tonic-gate * memory cannot be allocated, none of this information will be 9167c478bd9Sstevel@tonic-gate * saved. 9177c478bd9Sstevel@tonic-gate */ 918bd670b35SErik Nordmark ill_save_ire(ire->ire_ill, ire); 919bd670b35SErik Nordmark } 9207c478bd9Sstevel@tonic-gate 9217c478bd9Sstevel@tonic-gate if (ire_arg != NULL) { 9227c478bd9Sstevel@tonic-gate /* 9237c478bd9Sstevel@tonic-gate * Store the ire that was successfully added into where ire_arg 9247c478bd9Sstevel@tonic-gate * points to so that callers don't have to look it up 9257c478bd9Sstevel@tonic-gate * themselves (but they are responsible for ire_refrele()ing 9267c478bd9Sstevel@tonic-gate * the ire when they are finished with it). 9277c478bd9Sstevel@tonic-gate */ 9287c478bd9Sstevel@tonic-gate *ire_arg = ire; 9297c478bd9Sstevel@tonic-gate } else { 9307c478bd9Sstevel@tonic-gate ire_refrele(ire); /* Held in ire_add */ 9317c478bd9Sstevel@tonic-gate } 932bd670b35SErik Nordmark if (ipif != NULL) 9337c478bd9Sstevel@tonic-gate ipif_refrele(ipif); 9347c478bd9Sstevel@tonic-gate return (0); 9357c478bd9Sstevel@tonic-gate } 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate /* 9387c478bd9Sstevel@tonic-gate * ip_rt_delete_v6 is called to delete an IPv6 route. 939bd670b35SErik Nordmark * ill is passed in to associate it with the correct interface. 9407c478bd9Sstevel@tonic-gate * (for link-local destinations and gateways). 9417c478bd9Sstevel@tonic-gate */ 9427c478bd9Sstevel@tonic-gate /* ARGSUSED4 */ 9437c478bd9Sstevel@tonic-gate int 9447c478bd9Sstevel@tonic-gate ip_rt_delete_v6(const in6_addr_t *dst_addr, const in6_addr_t *mask, 945bd670b35SErik Nordmark const in6_addr_t *gw_addr, uint_t rtm_addrs, int flags, ill_t *ill, 946bd670b35SErik Nordmark ip_stack_t *ipst, zoneid_t zoneid) 9477c478bd9Sstevel@tonic-gate { 9487c478bd9Sstevel@tonic-gate ire_t *ire = NULL; 9497c478bd9Sstevel@tonic-gate ipif_t *ipif; 9507c478bd9Sstevel@tonic-gate uint_t type; 9517c478bd9Sstevel@tonic-gate uint_t match_flags = MATCH_IRE_TYPE; 9527c478bd9Sstevel@tonic-gate int err = 0; 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate /* 9557c478bd9Sstevel@tonic-gate * If this is the case of RTF_HOST being set, then we set the netmask 9567c478bd9Sstevel@tonic-gate * to all ones. Otherwise, we use the netmask if one was supplied. 9577c478bd9Sstevel@tonic-gate */ 9587c478bd9Sstevel@tonic-gate if (flags & RTF_HOST) { 9597c478bd9Sstevel@tonic-gate mask = &ipv6_all_ones; 9607c478bd9Sstevel@tonic-gate match_flags |= MATCH_IRE_MASK; 9617c478bd9Sstevel@tonic-gate } else if (rtm_addrs & RTA_NETMASK) { 9627c478bd9Sstevel@tonic-gate match_flags |= MATCH_IRE_MASK; 9637c478bd9Sstevel@tonic-gate } 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate /* 9667c478bd9Sstevel@tonic-gate * Note that RTF_GATEWAY is never set on a delete, therefore 9677c478bd9Sstevel@tonic-gate * we check if the gateway address is one of our interfaces first, 9687c478bd9Sstevel@tonic-gate * and fall back on RTF_GATEWAY routes. 9697c478bd9Sstevel@tonic-gate * 9707c478bd9Sstevel@tonic-gate * This makes it possible to delete an original 9717c478bd9Sstevel@tonic-gate * IRE_IF_NORESOLVER/IRE_IF_RESOLVER - consistent with SunOS 4.1. 972bd670b35SErik Nordmark * However, we have RTF_KERNEL set on the ones created by ipif_up 973bd670b35SErik Nordmark * and those can not be deleted here. 9747c478bd9Sstevel@tonic-gate * 975bd670b35SErik Nordmark * We use MATCH_IRE_ILL if we know the interface. If the caller 976bd670b35SErik Nordmark * specified an interface (from the RTA_IFP sockaddr) we use it, 977bd670b35SErik Nordmark * otherwise we use the ill derived from the gateway address. 978bd670b35SErik Nordmark * We can always match the gateway address since we record it 979bd670b35SErik Nordmark * in ire_gateway_addr. 9807c478bd9Sstevel@tonic-gate * 9817c478bd9Sstevel@tonic-gate * For more detail on specifying routes by gateway address and by 9827c478bd9Sstevel@tonic-gate * interface index, see the comments in ip_rt_add_v6(). 9837c478bd9Sstevel@tonic-gate */ 984bd670b35SErik Nordmark ipif = ipif_lookup_interface_v6(gw_addr, dst_addr, ipst); 9857c478bd9Sstevel@tonic-gate if (ipif != NULL) { 986bd670b35SErik Nordmark ill_t *ill_match; 987bd670b35SErik Nordmark 988bd670b35SErik Nordmark if (ill != NULL) 989bd670b35SErik Nordmark ill_match = ill; 990bd670b35SErik Nordmark else 991bd670b35SErik Nordmark ill_match = ipif->ipif_ill; 992bd670b35SErik Nordmark 9937c478bd9Sstevel@tonic-gate match_flags |= MATCH_IRE_ILL; 994bd670b35SErik Nordmark if (ipif->ipif_ire_type == IRE_LOOPBACK) { 995c57e370fSErik Nordmark ire = ire_ftable_lookup_v6(dst_addr, mask, 0, 996c57e370fSErik Nordmark IRE_LOOPBACK, ill_match, ALL_ZONES, NULL, 997c57e370fSErik Nordmark match_flags, 0, ipst, NULL); 998bd670b35SErik Nordmark } 999bd670b35SErik Nordmark if (ire == NULL) { 1000bd670b35SErik Nordmark match_flags |= MATCH_IRE_GW; 1001bd670b35SErik Nordmark ire = ire_ftable_lookup_v6(dst_addr, mask, gw_addr, 1002bd670b35SErik Nordmark IRE_INTERFACE, ill_match, ALL_ZONES, NULL, 1003bd670b35SErik Nordmark match_flags, 0, ipst, NULL); 1004bd670b35SErik Nordmark } 1005bd670b35SErik Nordmark /* Avoid deleting routes created by kernel from an ipif */ 1006bd670b35SErik Nordmark if (ire != NULL && (ire->ire_flags & RTF_KERNEL)) { 1007bd670b35SErik Nordmark ire_refrele(ire); 1008bd670b35SErik Nordmark ire = NULL; 10097c478bd9Sstevel@tonic-gate } 10107c478bd9Sstevel@tonic-gate 1011bd670b35SErik Nordmark /* Restore in case we didn't find a match */ 1012bd670b35SErik Nordmark match_flags &= ~(MATCH_IRE_GW|MATCH_IRE_ILL); 10137c478bd9Sstevel@tonic-gate } 1014bd670b35SErik Nordmark 10157c478bd9Sstevel@tonic-gate if (ire == NULL) { 10167c478bd9Sstevel@tonic-gate /* 10177c478bd9Sstevel@tonic-gate * At this point, the gateway address is not one of our own 10187c478bd9Sstevel@tonic-gate * addresses or a matching interface route was not found. We 10197c478bd9Sstevel@tonic-gate * set the IRE type to lookup based on whether 10207c478bd9Sstevel@tonic-gate * this is a host route, a default route or just a prefix. 10217c478bd9Sstevel@tonic-gate * 1022bd670b35SErik Nordmark * If an ill was passed in, then the lookup is based on an 10237c478bd9Sstevel@tonic-gate * interface index so MATCH_IRE_ILL is added to match_flags. 10247c478bd9Sstevel@tonic-gate */ 10257c478bd9Sstevel@tonic-gate match_flags |= MATCH_IRE_GW; 1026bd670b35SErik Nordmark if (ill != NULL) 10277c478bd9Sstevel@tonic-gate match_flags |= MATCH_IRE_ILL; 10287c478bd9Sstevel@tonic-gate if (IN6_ARE_ADDR_EQUAL(mask, &ipv6_all_ones)) 10297c478bd9Sstevel@tonic-gate type = IRE_HOST; 10307c478bd9Sstevel@tonic-gate else if (IN6_IS_ADDR_UNSPECIFIED(mask)) 10317c478bd9Sstevel@tonic-gate type = IRE_DEFAULT; 10327c478bd9Sstevel@tonic-gate else 10337c478bd9Sstevel@tonic-gate type = IRE_PREFIX; 10347c478bd9Sstevel@tonic-gate ire = ire_ftable_lookup_v6(dst_addr, mask, gw_addr, type, 1035bd670b35SErik Nordmark ill, ALL_ZONES, NULL, match_flags, 0, ipst, NULL); 10367c478bd9Sstevel@tonic-gate } 10377c478bd9Sstevel@tonic-gate 1038bd670b35SErik Nordmark if (ipif != NULL) { 10397c478bd9Sstevel@tonic-gate ipif_refrele(ipif); 1040bd670b35SErik Nordmark ipif = NULL; 10417c478bd9Sstevel@tonic-gate } 10427c478bd9Sstevel@tonic-gate if (ire == NULL) 10437c478bd9Sstevel@tonic-gate return (ESRCH); 10447c478bd9Sstevel@tonic-gate 10457c478bd9Sstevel@tonic-gate if (ire->ire_flags & RTF_MULTIRT) { 10467c478bd9Sstevel@tonic-gate /* 10477c478bd9Sstevel@tonic-gate * Invoke the CGTP (multirouting) filtering module 10487c478bd9Sstevel@tonic-gate * to remove the dst address from the filtering database. 10497c478bd9Sstevel@tonic-gate * Packets coming from that address will no longer be 10507c478bd9Sstevel@tonic-gate * filtered to remove duplicates. 10517c478bd9Sstevel@tonic-gate */ 1052655a42e2Snordmark if (ipst->ips_ip_cgtp_filter_ops != NULL) { 1053655a42e2Snordmark err = ipst->ips_ip_cgtp_filter_ops->cfo_del_dest_v6( 1054655a42e2Snordmark ipst->ips_netstack->netstack_stackid, 10557c478bd9Sstevel@tonic-gate &ire->ire_addr_v6, &ire->ire_gateway_addr_v6); 10567c478bd9Sstevel@tonic-gate } 10577c478bd9Sstevel@tonic-gate } 10587c478bd9Sstevel@tonic-gate 1059bd670b35SErik Nordmark ill = ire->ire_ill; 1060bd670b35SErik Nordmark if (ill != NULL) 1061bd670b35SErik Nordmark ill_remove_saved_ire(ill, ire); 10627c478bd9Sstevel@tonic-gate ire_delete(ire); 10637c478bd9Sstevel@tonic-gate ire_refrele(ire); 10647c478bd9Sstevel@tonic-gate return (err); 10657c478bd9Sstevel@tonic-gate } 10667c478bd9Sstevel@tonic-gate 10677c478bd9Sstevel@tonic-gate /* 10682b24ab6bSSebastien Roy * Derive an interface id from the link layer address. 10697c478bd9Sstevel@tonic-gate */ 10702b24ab6bSSebastien Roy void 10717c478bd9Sstevel@tonic-gate ill_setdefaulttoken(ill_t *ill) 10727c478bd9Sstevel@tonic-gate { 10732c5eb6feSSebastien Roy if (!ill->ill_manual_token) { 10742b24ab6bSSebastien Roy bzero(&ill->ill_token, sizeof (ill->ill_token)); 10752b24ab6bSSebastien Roy MEDIA_V6INTFID(ill->ill_media, ill, &ill->ill_token); 10767c478bd9Sstevel@tonic-gate ill->ill_token_length = IPV6_TOKEN_LEN; 10772b24ab6bSSebastien Roy } 10782b24ab6bSSebastien Roy } 10792b24ab6bSSebastien Roy 10802b24ab6bSSebastien Roy void 10812b24ab6bSSebastien Roy ill_setdesttoken(ill_t *ill) 10822b24ab6bSSebastien Roy { 10832b24ab6bSSebastien Roy bzero(&ill->ill_dest_token, sizeof (ill->ill_dest_token)); 10842b24ab6bSSebastien Roy MEDIA_V6DESTINTFID(ill->ill_media, ill, &ill->ill_dest_token); 10857c478bd9Sstevel@tonic-gate } 10867c478bd9Sstevel@tonic-gate 10877c478bd9Sstevel@tonic-gate /* 10887c478bd9Sstevel@tonic-gate * Create a link-local address from a token. 10897c478bd9Sstevel@tonic-gate */ 10907c478bd9Sstevel@tonic-gate static void 10917c478bd9Sstevel@tonic-gate ipif_get_linklocal(in6_addr_t *dest, const in6_addr_t *token) 10927c478bd9Sstevel@tonic-gate { 10937c478bd9Sstevel@tonic-gate int i; 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++) { 10967c478bd9Sstevel@tonic-gate dest->s6_addr32[i] = 10977c478bd9Sstevel@tonic-gate token->s6_addr32[i] | ipv6_ll_template.s6_addr32[i]; 10987c478bd9Sstevel@tonic-gate } 10997c478bd9Sstevel@tonic-gate } 11007c478bd9Sstevel@tonic-gate 11017c478bd9Sstevel@tonic-gate /* 11022b24ab6bSSebastien Roy * Set a default IPv6 address for a 6to4 tunnel interface 2002:<tsrc>::1/16 11037c478bd9Sstevel@tonic-gate */ 11047c478bd9Sstevel@tonic-gate static void 11052b24ab6bSSebastien Roy ipif_set6to4addr(ipif_t *ipif) 11067c478bd9Sstevel@tonic-gate { 11077c478bd9Sstevel@tonic-gate ill_t *ill = ipif->ipif_ill; 11082b24ab6bSSebastien Roy struct in_addr v4phys; 11097c478bd9Sstevel@tonic-gate 11102b24ab6bSSebastien Roy ASSERT(ill->ill_mactype == DL_6TO4); 11112b24ab6bSSebastien Roy ASSERT(ill->ill_phys_addr_length == sizeof (struct in_addr)); 11122b24ab6bSSebastien Roy ASSERT(ipif->ipif_isv6); 11132b24ab6bSSebastien Roy 11142b24ab6bSSebastien Roy if (ipif->ipif_flags & IPIF_UP) 11157c478bd9Sstevel@tonic-gate return; 11167c478bd9Sstevel@tonic-gate 11172b24ab6bSSebastien Roy (void) ip_plen_to_mask_v6(16, &ipif->ipif_v6net_mask); 11182b24ab6bSSebastien Roy bcopy(ill->ill_phys_addr, &v4phys, sizeof (struct in_addr)); 11192b24ab6bSSebastien Roy IN6_V4ADDR_TO_6TO4(&v4phys, &ipif->ipif_v6lcl_addr); 11202b24ab6bSSebastien Roy V6_MASK_COPY(ipif->ipif_v6lcl_addr, ipif->ipif_v6net_mask, 11212b24ab6bSSebastien Roy ipif->ipif_v6subnet); 11227c478bd9Sstevel@tonic-gate } 11237c478bd9Sstevel@tonic-gate 11247c478bd9Sstevel@tonic-gate /* 11257c478bd9Sstevel@tonic-gate * Is it not possible to set the link local address? 11267c478bd9Sstevel@tonic-gate * The address can be set if the token is set, and the token 11277c478bd9Sstevel@tonic-gate * isn't too long. 11287c478bd9Sstevel@tonic-gate * Return B_TRUE if the address can't be set, or B_FALSE if it can. 11297c478bd9Sstevel@tonic-gate */ 11307c478bd9Sstevel@tonic-gate boolean_t 11317c478bd9Sstevel@tonic-gate ipif_cant_setlinklocal(ipif_t *ipif) 11327c478bd9Sstevel@tonic-gate { 11337c478bd9Sstevel@tonic-gate ill_t *ill = ipif->ipif_ill; 11347c478bd9Sstevel@tonic-gate 11357c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(&ill->ill_token) || 11367c478bd9Sstevel@tonic-gate ill->ill_token_length > IPV6_ABITS - IPV6_LL_PREFIXLEN) 11377c478bd9Sstevel@tonic-gate return (B_TRUE); 11387c478bd9Sstevel@tonic-gate 11397c478bd9Sstevel@tonic-gate return (B_FALSE); 11407c478bd9Sstevel@tonic-gate } 11417c478bd9Sstevel@tonic-gate 11427c478bd9Sstevel@tonic-gate /* 11437c478bd9Sstevel@tonic-gate * Generate a link-local address from the token. 11447c478bd9Sstevel@tonic-gate */ 11452b24ab6bSSebastien Roy void 11467c478bd9Sstevel@tonic-gate ipif_setlinklocal(ipif_t *ipif) 11477c478bd9Sstevel@tonic-gate { 11487c478bd9Sstevel@tonic-gate ill_t *ill = ipif->ipif_ill; 11496e844434Svi117747 in6_addr_t ov6addr; 11507c478bd9Sstevel@tonic-gate 11517c478bd9Sstevel@tonic-gate ASSERT(IAM_WRITER_ILL(ill)); 11527c478bd9Sstevel@tonic-gate 11532b24ab6bSSebastien Roy /* 11546e91bba0SGirish Moodalbail * If the interface was created with no link-local address 11556e91bba0SGirish Moodalbail * on it and the flag ILLF_NOLINKLOCAL was set, then we 11566e91bba0SGirish Moodalbail * dont want to update the link-local. 11576e91bba0SGirish Moodalbail */ 11586e91bba0SGirish Moodalbail if ((ill->ill_flags & ILLF_NOLINKLOCAL) && 11596e91bba0SGirish Moodalbail IN6_IS_ADDR_UNSPECIFIED(&ipif->ipif_v6lcl_addr)) 11606e91bba0SGirish Moodalbail return; 11616e91bba0SGirish Moodalbail /* 11622b24ab6bSSebastien Roy * ill_manual_linklocal is set when the link-local address was 11632b24ab6bSSebastien Roy * manually configured. 11642b24ab6bSSebastien Roy */ 11652b24ab6bSSebastien Roy if (ill->ill_manual_linklocal) 11662b24ab6bSSebastien Roy return; 11672b24ab6bSSebastien Roy 11682b24ab6bSSebastien Roy /* 11692b24ab6bSSebastien Roy * IPv6 interfaces over 6to4 tunnels are special. They do not have 11702b24ab6bSSebastien Roy * link-local addresses, but instead have a single automatically 11712b24ab6bSSebastien Roy * generated global address. 11722b24ab6bSSebastien Roy */ 11732b24ab6bSSebastien Roy if (ill->ill_mactype == DL_6TO4) { 11742b24ab6bSSebastien Roy ipif_set6to4addr(ipif); 11752b24ab6bSSebastien Roy return; 11762b24ab6bSSebastien Roy } 11772b24ab6bSSebastien Roy 11787c478bd9Sstevel@tonic-gate if (ipif_cant_setlinklocal(ipif)) 11792b24ab6bSSebastien Roy return; 11807c478bd9Sstevel@tonic-gate 11816e844434Svi117747 ov6addr = ipif->ipif_v6lcl_addr; 11827c478bd9Sstevel@tonic-gate ipif_get_linklocal(&ipif->ipif_v6lcl_addr, &ill->ill_token); 11836e844434Svi117747 sctp_update_ipif_addr(ipif, ov6addr); 11847c478bd9Sstevel@tonic-gate (void) ip_plen_to_mask_v6(IPV6_LL_PREFIXLEN, &ipif->ipif_v6net_mask); 11852b24ab6bSSebastien Roy if (IN6_IS_ADDR_UNSPECIFIED(&ipif->ipif_v6pp_dst_addr)) { 11867c478bd9Sstevel@tonic-gate V6_MASK_COPY(ipif->ipif_v6lcl_addr, ipif->ipif_v6net_mask, 11877c478bd9Sstevel@tonic-gate ipif->ipif_v6subnet); 11882b24ab6bSSebastien Roy } 11897c478bd9Sstevel@tonic-gate 11901cb875aeSCathy Zhou ip_rts_newaddrmsg(RTM_CHGADDR, 0, ipif, RTSQ_DEFAULT); 11912b24ab6bSSebastien Roy } 11922b24ab6bSSebastien Roy 11932b24ab6bSSebastien Roy /* 1194792bd779SSebastien Roy * Generate a destination link-local address for a point-to-point IPv6 1195792bd779SSebastien Roy * interface with a destination interface id (IP tunnels are such interfaces) 1196792bd779SSebastien Roy * based on the destination token. 11972b24ab6bSSebastien Roy */ 11982b24ab6bSSebastien Roy void 11992b24ab6bSSebastien Roy ipif_setdestlinklocal(ipif_t *ipif) 12002b24ab6bSSebastien Roy { 12012b24ab6bSSebastien Roy ill_t *ill = ipif->ipif_ill; 12022b24ab6bSSebastien Roy 12032b24ab6bSSebastien Roy ASSERT(IAM_WRITER_ILL(ill)); 1204792bd779SSebastien Roy 1205792bd779SSebastien Roy if (ill->ill_manual_dst_linklocal) 12062b24ab6bSSebastien Roy return; 1207792bd779SSebastien Roy 1208792bd779SSebastien Roy if (IN6_IS_ADDR_UNSPECIFIED(&ill->ill_dest_token)) 1209bd670b35SErik Nordmark return; 1210bd670b35SErik Nordmark 12112b24ab6bSSebastien Roy ipif_get_linklocal(&ipif->ipif_v6pp_dst_addr, &ill->ill_dest_token); 12122b24ab6bSSebastien Roy ipif->ipif_v6subnet = ipif->ipif_v6pp_dst_addr; 12137c478bd9Sstevel@tonic-gate } 12147c478bd9Sstevel@tonic-gate 12157c478bd9Sstevel@tonic-gate /* 121698e93c29Smeem * Get the resolver set up for a new ipif. (Always called as writer.) 12177c478bd9Sstevel@tonic-gate */ 12187c478bd9Sstevel@tonic-gate int 1219e11c3f44Smeem ipif_ndp_up(ipif_t *ipif, boolean_t initial) 12207c478bd9Sstevel@tonic-gate { 12217c478bd9Sstevel@tonic-gate ill_t *ill = ipif->ipif_ill; 12227c478bd9Sstevel@tonic-gate int err = 0; 12237c478bd9Sstevel@tonic-gate nce_t *nce = NULL; 1224e11c3f44Smeem boolean_t added_ipif = B_FALSE; 12257c478bd9Sstevel@tonic-gate 1226bd670b35SErik Nordmark DTRACE_PROBE3(ipif__downup, char *, "ipif_ndp_up", 1227bd670b35SErik Nordmark ill_t *, ill, ipif_t *, ipif); 122898e93c29Smeem ip1dbg(("ipif_ndp_up(%s:%u)\n", ill->ill_name, ipif->ipif_id)); 12297c478bd9Sstevel@tonic-gate 1230bd670b35SErik Nordmark if (IN6_IS_ADDR_UNSPECIFIED(&ipif->ipif_v6lcl_addr) || 123169bb4bb4Scarlsonj (!(ill->ill_net_type & IRE_INTERFACE))) { 123269bb4bb4Scarlsonj ipif->ipif_addr_ready = 1; 12337c478bd9Sstevel@tonic-gate return (0); 123469bb4bb4Scarlsonj } 12357c478bd9Sstevel@tonic-gate 12367c478bd9Sstevel@tonic-gate if ((ipif->ipif_flags & (IPIF_UNNUMBERED|IPIF_NOLOCAL)) == 0) { 12377c478bd9Sstevel@tonic-gate uint16_t flags; 1238e11c3f44Smeem uint16_t state; 1239bd670b35SErik Nordmark uchar_t *hw_addr; 1240e11c3f44Smeem ill_t *bound_ill; 1241e11c3f44Smeem ipmp_illgrp_t *illg = ill->ill_grp; 1242bd670b35SErik Nordmark uint_t hw_addr_len; 12437c478bd9Sstevel@tonic-gate 1244bd670b35SErik Nordmark flags = NCE_F_MYADDR | NCE_F_NONUD | NCE_F_PUBLISH | 1245bd670b35SErik Nordmark NCE_F_AUTHORITY; 12467c478bd9Sstevel@tonic-gate if (ill->ill_flags & ILLF_ROUTER) 12477c478bd9Sstevel@tonic-gate flags |= NCE_F_ISROUTER; 12487c478bd9Sstevel@tonic-gate 12497c478bd9Sstevel@tonic-gate if (ipif->ipif_flags & IPIF_ANYCAST) 12507c478bd9Sstevel@tonic-gate flags |= NCE_F_ANYCAST; 12517c478bd9Sstevel@tonic-gate 1252e11c3f44Smeem if (IS_IPMP(ill)) { 1253e11c3f44Smeem ASSERT(ill->ill_net_type == IRE_IF_RESOLVER); 12547c478bd9Sstevel@tonic-gate /* 1255e11c3f44Smeem * If we're here via ipif_up(), then the ipif won't be 1256e11c3f44Smeem * bound yet -- add it to the group, which will bind 1257e11c3f44Smeem * it if possible. (We would add it in ipif_up(), but 1258e11c3f44Smeem * deleting on failure there is gruesome.) If we're 1259e11c3f44Smeem * here via ipmp_ill_bind_ipif(), then the ipif has 1260e11c3f44Smeem * already been added to the group and we just need to 1261e11c3f44Smeem * use the binding. 12627c478bd9Sstevel@tonic-gate */ 1263e11c3f44Smeem if ((bound_ill = ipmp_ipif_bound_ill(ipif)) == NULL) { 1264e11c3f44Smeem bound_ill = ipmp_illgrp_add_ipif(illg, ipif); 1265e11c3f44Smeem if (bound_ill == NULL) { 1266e11c3f44Smeem /* 1267e11c3f44Smeem * We couldn't bind the ipif to an ill 1268e11c3f44Smeem * yet, so we have nothing to publish. 1269e11c3f44Smeem * Set ipif_addr_ready so that this 1270e11c3f44Smeem * address can be used locally for now. 1271e11c3f44Smeem * The routing socket message will be 1272e11c3f44Smeem * sent from ipif_up_done_v6(). 1273e11c3f44Smeem */ 1274e11c3f44Smeem ipif->ipif_addr_ready = 1; 1275e11c3f44Smeem return (0); 1276e11c3f44Smeem } 1277e11c3f44Smeem added_ipif = B_TRUE; 1278e11c3f44Smeem } 1279e11c3f44Smeem hw_addr = bound_ill->ill_nd_lla; 1280bd670b35SErik Nordmark hw_addr_len = bound_ill->ill_phys_addr_length; 1281e11c3f44Smeem } else { 1282e11c3f44Smeem bound_ill = ill; 1283e11c3f44Smeem hw_addr = ill->ill_nd_lla; 1284bd670b35SErik Nordmark hw_addr_len = ill->ill_phys_addr_length; 1285e11c3f44Smeem } 1286e11c3f44Smeem 1287e11c3f44Smeem /* 1288e11c3f44Smeem * If this is an initial bring-up (or the ipif was never 1289e11c3f44Smeem * completely brought up), do DAD. Otherwise, we're here 1290e11c3f44Smeem * because IPMP has rebound an address to this ill: send 1291e11c3f44Smeem * unsolicited advertisements to inform others. 1292e11c3f44Smeem */ 1293e11c3f44Smeem if (initial || !ipif->ipif_addr_ready) { 1294bd670b35SErik Nordmark /* Causes Duplicate Address Detection to run */ 1295e11c3f44Smeem state = ND_PROBE; 1296e11c3f44Smeem } else { 1297e11c3f44Smeem state = ND_REACHABLE; 12987c478bd9Sstevel@tonic-gate flags |= NCE_F_UNSOL_ADV; 12997c478bd9Sstevel@tonic-gate } 1300bd670b35SErik Nordmark 1301f7ed54c4SSowmini Varadhan retry: 1302bd670b35SErik Nordmark err = nce_lookup_then_add_v6(ill, hw_addr, hw_addr_len, 1303bd670b35SErik Nordmark &ipif->ipif_v6lcl_addr, flags, state, &nce); 13047c478bd9Sstevel@tonic-gate switch (err) { 13057c478bd9Sstevel@tonic-gate case 0: 13067c478bd9Sstevel@tonic-gate ip1dbg(("ipif_ndp_up: NCE created for %s\n", 13077c478bd9Sstevel@tonic-gate ill->ill_name)); 130869bb4bb4Scarlsonj ipif->ipif_addr_ready = 1; 13099294ad19SSowmini Varadhan ipif->ipif_added_nce = 1; 13103efde6d0SSowmini Varadhan nce->nce_ipif_cnt++; 131169bb4bb4Scarlsonj break; 131269bb4bb4Scarlsonj case EINPROGRESS: 131369bb4bb4Scarlsonj ip1dbg(("ipif_ndp_up: running DAD now for %s\n", 131469bb4bb4Scarlsonj ill->ill_name)); 13159294ad19SSowmini Varadhan ipif->ipif_added_nce = 1; 13163efde6d0SSowmini Varadhan nce->nce_ipif_cnt++; 13177c478bd9Sstevel@tonic-gate break; 13187c478bd9Sstevel@tonic-gate case EEXIST: 13197c478bd9Sstevel@tonic-gate ip1dbg(("ipif_ndp_up: NCE already exists for %s\n", 13207c478bd9Sstevel@tonic-gate ill->ill_name)); 1321bd670b35SErik Nordmark if (!NCE_MYADDR(nce->nce_common)) { 1322bd670b35SErik Nordmark /* 1323bd670b35SErik Nordmark * A leftover nce from before this address 1324bd670b35SErik Nordmark * existed 1325bd670b35SErik Nordmark */ 1326bd670b35SErik Nordmark ncec_delete(nce->nce_common); 1327bd670b35SErik Nordmark nce_refrele(nce); 1328f7ed54c4SSowmini Varadhan nce = NULL; 1329f7ed54c4SSowmini Varadhan goto retry; 1330f7ed54c4SSowmini Varadhan } 13313efde6d0SSowmini Varadhan if ((ipif->ipif_flags & IPIF_POINTOPOINT) == 0) { 1332bd670b35SErik Nordmark nce_refrele(nce); 1333bd670b35SErik Nordmark nce = NULL; 1334bd670b35SErik Nordmark ip1dbg(("ipif_ndp_up: NCE already exists " 1335bd670b35SErik Nordmark "for %s\n", ill->ill_name)); 1336e11c3f44Smeem goto fail; 13373efde6d0SSowmini Varadhan } 13383efde6d0SSowmini Varadhan /* 13393efde6d0SSowmini Varadhan * Duplicate local addresses are permissible for 13403efde6d0SSowmini Varadhan * IPIF_POINTOPOINT interfaces which will get marked 13413efde6d0SSowmini Varadhan * IPIF_UNNUMBERED later in 13423efde6d0SSowmini Varadhan * ip_addr_availability_check(). 13433efde6d0SSowmini Varadhan * 13443efde6d0SSowmini Varadhan * The nce_ipif_cnt field tracks the number of 13453efde6d0SSowmini Varadhan * ipifs that have nce_addr as their local address. 13463efde6d0SSowmini Varadhan */ 13473efde6d0SSowmini Varadhan ipif->ipif_addr_ready = 1; 13483efde6d0SSowmini Varadhan ipif->ipif_added_nce = 1; 13493efde6d0SSowmini Varadhan nce->nce_ipif_cnt++; 1350bd670b35SErik Nordmark err = 0; 13513efde6d0SSowmini Varadhan break; 13527c478bd9Sstevel@tonic-gate default: 1353e11c3f44Smeem ip1dbg(("ipif_ndp_up: NCE creation failed for %s\n", 13547c478bd9Sstevel@tonic-gate ill->ill_name)); 1355e11c3f44Smeem goto fail; 13567c478bd9Sstevel@tonic-gate } 135769bb4bb4Scarlsonj } else { 135869bb4bb4Scarlsonj /* No local NCE for this entry */ 135969bb4bb4Scarlsonj ipif->ipif_addr_ready = 1; 13607c478bd9Sstevel@tonic-gate } 13617c478bd9Sstevel@tonic-gate if (nce != NULL) 1362bd670b35SErik Nordmark nce_refrele(nce); 13637c478bd9Sstevel@tonic-gate return (0); 1364e11c3f44Smeem fail: 1365e11c3f44Smeem if (added_ipif) 1366e11c3f44Smeem ipmp_illgrp_del_ipif(ill->ill_grp, ipif); 1367e11c3f44Smeem 1368e11c3f44Smeem return (err); 13697c478bd9Sstevel@tonic-gate } 13707c478bd9Sstevel@tonic-gate 13717c478bd9Sstevel@tonic-gate /* Remove all cache entries for this logical interface */ 13727c478bd9Sstevel@tonic-gate void 13737c478bd9Sstevel@tonic-gate ipif_ndp_down(ipif_t *ipif) 13747c478bd9Sstevel@tonic-gate { 1375bd670b35SErik Nordmark ipif_nce_down(ipif); 13767c478bd9Sstevel@tonic-gate } 13777c478bd9Sstevel@tonic-gate 13787c478bd9Sstevel@tonic-gate /* 13797c478bd9Sstevel@tonic-gate * Return the scope of the given IPv6 address. If the address is an 13807c478bd9Sstevel@tonic-gate * IPv4 mapped IPv6 address, return the scope of the corresponding 13817c478bd9Sstevel@tonic-gate * IPv4 address. 13827c478bd9Sstevel@tonic-gate */ 13837c478bd9Sstevel@tonic-gate in6addr_scope_t 13847c478bd9Sstevel@tonic-gate ip_addr_scope_v6(const in6_addr_t *addr) 13857c478bd9Sstevel@tonic-gate { 13867c478bd9Sstevel@tonic-gate static in6_addr_t ipv6loopback = IN6ADDR_LOOPBACK_INIT; 13877c478bd9Sstevel@tonic-gate 13887c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(addr)) { 13897c478bd9Sstevel@tonic-gate in_addr_t v4addr_h = ntohl(V4_PART_OF_V6((*addr))); 13907c478bd9Sstevel@tonic-gate if ((v4addr_h >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET || 13917c478bd9Sstevel@tonic-gate (v4addr_h & IN_AUTOCONF_MASK) == IN_AUTOCONF_NET) 13927c478bd9Sstevel@tonic-gate return (IP6_SCOPE_LINKLOCAL); 13937c478bd9Sstevel@tonic-gate if ((v4addr_h & IN_PRIVATE8_MASK) == IN_PRIVATE8_NET || 13947c478bd9Sstevel@tonic-gate (v4addr_h & IN_PRIVATE12_MASK) == IN_PRIVATE12_NET || 13957c478bd9Sstevel@tonic-gate (v4addr_h & IN_PRIVATE16_MASK) == IN_PRIVATE16_NET) 13967c478bd9Sstevel@tonic-gate return (IP6_SCOPE_SITELOCAL); 13977c478bd9Sstevel@tonic-gate return (IP6_SCOPE_GLOBAL); 13987c478bd9Sstevel@tonic-gate } 13997c478bd9Sstevel@tonic-gate 14007c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_MULTICAST(addr)) 14017c478bd9Sstevel@tonic-gate return (IN6_ADDR_MC_SCOPE(addr)); 14027c478bd9Sstevel@tonic-gate 14037c478bd9Sstevel@tonic-gate /* link-local and loopback addresses are of link-local scope */ 14047c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_LINKLOCAL(addr) || 14057c478bd9Sstevel@tonic-gate IN6_ARE_ADDR_EQUAL(addr, &ipv6loopback)) 14067c478bd9Sstevel@tonic-gate return (IP6_SCOPE_LINKLOCAL); 14077c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_SITELOCAL(addr)) 14087c478bd9Sstevel@tonic-gate return (IP6_SCOPE_SITELOCAL); 14097c478bd9Sstevel@tonic-gate return (IP6_SCOPE_GLOBAL); 14107c478bd9Sstevel@tonic-gate } 14117c478bd9Sstevel@tonic-gate 14127c478bd9Sstevel@tonic-gate 14137c478bd9Sstevel@tonic-gate /* 1414d04ccbb3Scarlsonj * Returns the length of the common prefix of a1 and a2, as per 1415d04ccbb3Scarlsonj * CommonPrefixLen() defined in RFC 3484. 14167c478bd9Sstevel@tonic-gate */ 1417d04ccbb3Scarlsonj static int 1418d04ccbb3Scarlsonj ip_common_prefix_v6(const in6_addr_t *a1, const in6_addr_t *a2) 14197c478bd9Sstevel@tonic-gate { 14207c478bd9Sstevel@tonic-gate int i; 1421d04ccbb3Scarlsonj uint32_t a1val, a2val, mask; 14227c478bd9Sstevel@tonic-gate 1423d04ccbb3Scarlsonj for (i = 0; i < 4; i++) { 1424d04ccbb3Scarlsonj if ((a1val = a1->s6_addr32[i]) != (a2val = a2->s6_addr32[i])) { 1425d04ccbb3Scarlsonj a1val ^= a2val; 1426d04ccbb3Scarlsonj i *= 32; 1427d04ccbb3Scarlsonj mask = 0x80000000u; 1428d04ccbb3Scarlsonj while (!(a1val & mask)) { 1429d04ccbb3Scarlsonj mask >>= 1; 1430d04ccbb3Scarlsonj i++; 1431d04ccbb3Scarlsonj } 1432d04ccbb3Scarlsonj return (i); 1433d04ccbb3Scarlsonj } 1434d04ccbb3Scarlsonj } 1435d04ccbb3Scarlsonj return (IPV6_ABITS); 14367c478bd9Sstevel@tonic-gate } 14377c478bd9Sstevel@tonic-gate 14387c478bd9Sstevel@tonic-gate #define IPIF_VALID_IPV6_SOURCE(ipif) \ 14397c478bd9Sstevel@tonic-gate (((ipif)->ipif_flags & IPIF_UP) && \ 14401cb875aeSCathy Zhou !((ipif)->ipif_flags & (IPIF_NOLOCAL|IPIF_ANYCAST)) && \ 14411cb875aeSCathy Zhou !((ipif)->ipif_ill->ill_flags & ILLF_NOACCEPT)) 14427c478bd9Sstevel@tonic-gate 14437c478bd9Sstevel@tonic-gate /* source address candidate */ 14447c478bd9Sstevel@tonic-gate typedef struct candidate { 14457c478bd9Sstevel@tonic-gate ipif_t *cand_ipif; 14467c478bd9Sstevel@tonic-gate /* The properties of this candidate */ 14477c478bd9Sstevel@tonic-gate boolean_t cand_isdst; 14487c478bd9Sstevel@tonic-gate boolean_t cand_isdst_set; 14497c478bd9Sstevel@tonic-gate in6addr_scope_t cand_scope; 14507c478bd9Sstevel@tonic-gate boolean_t cand_scope_set; 14517c478bd9Sstevel@tonic-gate boolean_t cand_isdeprecated; 14527c478bd9Sstevel@tonic-gate boolean_t cand_isdeprecated_set; 14537c478bd9Sstevel@tonic-gate boolean_t cand_ispreferred; 14547c478bd9Sstevel@tonic-gate boolean_t cand_ispreferred_set; 14557c478bd9Sstevel@tonic-gate boolean_t cand_matchedinterface; 14567c478bd9Sstevel@tonic-gate boolean_t cand_matchedinterface_set; 14577c478bd9Sstevel@tonic-gate boolean_t cand_matchedlabel; 14587c478bd9Sstevel@tonic-gate boolean_t cand_matchedlabel_set; 14597c478bd9Sstevel@tonic-gate boolean_t cand_istmp; 14607c478bd9Sstevel@tonic-gate boolean_t cand_istmp_set; 1461d04ccbb3Scarlsonj int cand_common_pref; 1462d04ccbb3Scarlsonj boolean_t cand_common_pref_set; 1463d04ccbb3Scarlsonj boolean_t cand_pref_eq; 1464d04ccbb3Scarlsonj boolean_t cand_pref_eq_set; 1465d04ccbb3Scarlsonj int cand_pref_len; 1466d04ccbb3Scarlsonj boolean_t cand_pref_len_set; 14677c478bd9Sstevel@tonic-gate } cand_t; 14687c478bd9Sstevel@tonic-gate #define cand_srcaddr cand_ipif->ipif_v6lcl_addr 1469d04ccbb3Scarlsonj #define cand_mask cand_ipif->ipif_v6net_mask 14707c478bd9Sstevel@tonic-gate #define cand_flags cand_ipif->ipif_flags 14717c478bd9Sstevel@tonic-gate #define cand_ill cand_ipif->ipif_ill 147245916cd2Sjpk #define cand_zoneid cand_ipif->ipif_zoneid 14737c478bd9Sstevel@tonic-gate 14747c478bd9Sstevel@tonic-gate /* information about the destination for source address selection */ 14757c478bd9Sstevel@tonic-gate typedef struct dstinfo { 14767c478bd9Sstevel@tonic-gate const in6_addr_t *dst_addr; 14777c478bd9Sstevel@tonic-gate ill_t *dst_ill; 1478309fa174Srk129064 uint_t dst_restrict_ill; 14797c478bd9Sstevel@tonic-gate boolean_t dst_prefer_src_tmp; 14807c478bd9Sstevel@tonic-gate in6addr_scope_t dst_scope; 14817c478bd9Sstevel@tonic-gate char *dst_label; 14827c478bd9Sstevel@tonic-gate } dstinfo_t; 14837c478bd9Sstevel@tonic-gate 14847c478bd9Sstevel@tonic-gate /* 14857c478bd9Sstevel@tonic-gate * The following functions are rules used to select a source address in 14867c478bd9Sstevel@tonic-gate * ipif_select_source_v6(). Each rule compares a current candidate (cc) 14877c478bd9Sstevel@tonic-gate * against the best candidate (bc). Each rule has three possible outcomes; 14887c478bd9Sstevel@tonic-gate * the candidate is preferred over the best candidate (CAND_PREFER), the 14897c478bd9Sstevel@tonic-gate * candidate is not preferred over the best candidate (CAND_AVOID), or the 14907c478bd9Sstevel@tonic-gate * candidate is of equal value as the best candidate (CAND_TIE). 14917c478bd9Sstevel@tonic-gate * 14927c478bd9Sstevel@tonic-gate * These rules are part of a greater "Default Address Selection for IPv6" 14937c478bd9Sstevel@tonic-gate * sheme, which is standards based work coming out of the IETF ipv6 working 14947c478bd9Sstevel@tonic-gate * group. The IETF document defines both IPv6 source address selection and 14957c478bd9Sstevel@tonic-gate * destination address ordering. The rules defined here implement the IPv6 14967c478bd9Sstevel@tonic-gate * source address selection. Destination address ordering is done by 14977c478bd9Sstevel@tonic-gate * libnsl, and uses a similar set of rules to implement the sorting. 1498d04ccbb3Scarlsonj * 1499d04ccbb3Scarlsonj * Most of the rules are defined by the RFC and are not typically altered. The 1500d04ccbb3Scarlsonj * last rule, number 8, has language that allows for local preferences. In the 1501d04ccbb3Scarlsonj * scheme below, this means that new Solaris rules should normally go between 1502d04ccbb3Scarlsonj * rule_ifprefix and rule_prefix. 15037c478bd9Sstevel@tonic-gate */ 15047c478bd9Sstevel@tonic-gate typedef enum {CAND_AVOID, CAND_TIE, CAND_PREFER} rule_res_t; 1505f4b3ec61Sdh155122 typedef rule_res_t (*rulef_t)(cand_t *, cand_t *, const dstinfo_t *, 1506f4b3ec61Sdh155122 ip_stack_t *); 15077c478bd9Sstevel@tonic-gate 15087c478bd9Sstevel@tonic-gate /* Prefer an address if it is equal to the destination address. */ 1509f4b3ec61Sdh155122 /* ARGSUSED3 */ 15107c478bd9Sstevel@tonic-gate static rule_res_t 1511f4b3ec61Sdh155122 rule_isdst(cand_t *bc, cand_t *cc, const dstinfo_t *dstinfo, ip_stack_t *ipst) 15127c478bd9Sstevel@tonic-gate { 15137c478bd9Sstevel@tonic-gate if (!bc->cand_isdst_set) { 15147c478bd9Sstevel@tonic-gate bc->cand_isdst = 15157c478bd9Sstevel@tonic-gate IN6_ARE_ADDR_EQUAL(&bc->cand_srcaddr, dstinfo->dst_addr); 15167c478bd9Sstevel@tonic-gate bc->cand_isdst_set = B_TRUE; 15177c478bd9Sstevel@tonic-gate } 15187c478bd9Sstevel@tonic-gate 15197c478bd9Sstevel@tonic-gate cc->cand_isdst = 15207c478bd9Sstevel@tonic-gate IN6_ARE_ADDR_EQUAL(&cc->cand_srcaddr, dstinfo->dst_addr); 15217c478bd9Sstevel@tonic-gate cc->cand_isdst_set = B_TRUE; 15227c478bd9Sstevel@tonic-gate 15237c478bd9Sstevel@tonic-gate if (cc->cand_isdst == bc->cand_isdst) 15247c478bd9Sstevel@tonic-gate return (CAND_TIE); 15257c478bd9Sstevel@tonic-gate else if (cc->cand_isdst) 15267c478bd9Sstevel@tonic-gate return (CAND_PREFER); 15277c478bd9Sstevel@tonic-gate else 15287c478bd9Sstevel@tonic-gate return (CAND_AVOID); 15297c478bd9Sstevel@tonic-gate } 15307c478bd9Sstevel@tonic-gate 15317c478bd9Sstevel@tonic-gate /* 15327c478bd9Sstevel@tonic-gate * Prefer addresses that are of closest scope to the destination. Always 15337c478bd9Sstevel@tonic-gate * prefer addresses that are of greater scope than the destination over 15347c478bd9Sstevel@tonic-gate * those that are of lesser scope than the destination. 15357c478bd9Sstevel@tonic-gate */ 1536f4b3ec61Sdh155122 /* ARGSUSED3 */ 15377c478bd9Sstevel@tonic-gate static rule_res_t 1538f4b3ec61Sdh155122 rule_scope(cand_t *bc, cand_t *cc, const dstinfo_t *dstinfo, ip_stack_t *ipst) 15397c478bd9Sstevel@tonic-gate { 15407c478bd9Sstevel@tonic-gate if (!bc->cand_scope_set) { 15417c478bd9Sstevel@tonic-gate bc->cand_scope = ip_addr_scope_v6(&bc->cand_srcaddr); 15427c478bd9Sstevel@tonic-gate bc->cand_scope_set = B_TRUE; 15437c478bd9Sstevel@tonic-gate } 15447c478bd9Sstevel@tonic-gate 15457c478bd9Sstevel@tonic-gate cc->cand_scope = ip_addr_scope_v6(&cc->cand_srcaddr); 15467c478bd9Sstevel@tonic-gate cc->cand_scope_set = B_TRUE; 15477c478bd9Sstevel@tonic-gate 15487c478bd9Sstevel@tonic-gate if (cc->cand_scope < bc->cand_scope) { 15497c478bd9Sstevel@tonic-gate if (cc->cand_scope < dstinfo->dst_scope) 15507c478bd9Sstevel@tonic-gate return (CAND_AVOID); 15517c478bd9Sstevel@tonic-gate else 15527c478bd9Sstevel@tonic-gate return (CAND_PREFER); 15537c478bd9Sstevel@tonic-gate } else if (bc->cand_scope < cc->cand_scope) { 15547c478bd9Sstevel@tonic-gate if (bc->cand_scope < dstinfo->dst_scope) 15557c478bd9Sstevel@tonic-gate return (CAND_PREFER); 15567c478bd9Sstevel@tonic-gate else 15577c478bd9Sstevel@tonic-gate return (CAND_AVOID); 15587c478bd9Sstevel@tonic-gate } else { 15597c478bd9Sstevel@tonic-gate return (CAND_TIE); 15607c478bd9Sstevel@tonic-gate } 15617c478bd9Sstevel@tonic-gate } 15627c478bd9Sstevel@tonic-gate 15637c478bd9Sstevel@tonic-gate /* 15647c478bd9Sstevel@tonic-gate * Prefer non-deprecated source addresses. 15657c478bd9Sstevel@tonic-gate */ 15667c478bd9Sstevel@tonic-gate /* ARGSUSED2 */ 15677c478bd9Sstevel@tonic-gate static rule_res_t 1568f4b3ec61Sdh155122 rule_deprecated(cand_t *bc, cand_t *cc, const dstinfo_t *dstinfo, 1569f4b3ec61Sdh155122 ip_stack_t *ipst) 15707c478bd9Sstevel@tonic-gate { 15717c478bd9Sstevel@tonic-gate if (!bc->cand_isdeprecated_set) { 15727c478bd9Sstevel@tonic-gate bc->cand_isdeprecated = 15737c478bd9Sstevel@tonic-gate ((bc->cand_flags & IPIF_DEPRECATED) != 0); 15747c478bd9Sstevel@tonic-gate bc->cand_isdeprecated_set = B_TRUE; 15757c478bd9Sstevel@tonic-gate } 15767c478bd9Sstevel@tonic-gate 15777c478bd9Sstevel@tonic-gate cc->cand_isdeprecated = ((cc->cand_flags & IPIF_DEPRECATED) != 0); 15787c478bd9Sstevel@tonic-gate cc->cand_isdeprecated_set = B_TRUE; 15797c478bd9Sstevel@tonic-gate 15807c478bd9Sstevel@tonic-gate if (bc->cand_isdeprecated == cc->cand_isdeprecated) 15817c478bd9Sstevel@tonic-gate return (CAND_TIE); 15827c478bd9Sstevel@tonic-gate else if (cc->cand_isdeprecated) 15837c478bd9Sstevel@tonic-gate return (CAND_AVOID); 15847c478bd9Sstevel@tonic-gate else 15857c478bd9Sstevel@tonic-gate return (CAND_PREFER); 15867c478bd9Sstevel@tonic-gate } 15877c478bd9Sstevel@tonic-gate 15887c478bd9Sstevel@tonic-gate /* 15897c478bd9Sstevel@tonic-gate * Prefer source addresses that have the IPIF_PREFERRED flag set. This 15907c478bd9Sstevel@tonic-gate * rule must be before rule_interface because the flag could be set on any 15917c478bd9Sstevel@tonic-gate * interface, not just the interface being used for outgoing packets (for 15927c478bd9Sstevel@tonic-gate * example, the IFF_PREFERRED could be set on an address assigned to the 15937c478bd9Sstevel@tonic-gate * loopback interface). 15947c478bd9Sstevel@tonic-gate */ 15957c478bd9Sstevel@tonic-gate /* ARGSUSED2 */ 15967c478bd9Sstevel@tonic-gate static rule_res_t 1597f4b3ec61Sdh155122 rule_preferred(cand_t *bc, cand_t *cc, const dstinfo_t *dstinfo, 1598f4b3ec61Sdh155122 ip_stack_t *ipst) 15997c478bd9Sstevel@tonic-gate { 16007c478bd9Sstevel@tonic-gate if (!bc->cand_ispreferred_set) { 16017c478bd9Sstevel@tonic-gate bc->cand_ispreferred = ((bc->cand_flags & IPIF_PREFERRED) != 0); 16027c478bd9Sstevel@tonic-gate bc->cand_ispreferred_set = B_TRUE; 16037c478bd9Sstevel@tonic-gate } 16047c478bd9Sstevel@tonic-gate 16057c478bd9Sstevel@tonic-gate cc->cand_ispreferred = ((cc->cand_flags & IPIF_PREFERRED) != 0); 16067c478bd9Sstevel@tonic-gate cc->cand_ispreferred_set = B_TRUE; 16077c478bd9Sstevel@tonic-gate 16087c478bd9Sstevel@tonic-gate if (bc->cand_ispreferred == cc->cand_ispreferred) 16097c478bd9Sstevel@tonic-gate return (CAND_TIE); 16107c478bd9Sstevel@tonic-gate else if (cc->cand_ispreferred) 16117c478bd9Sstevel@tonic-gate return (CAND_PREFER); 16127c478bd9Sstevel@tonic-gate else 16137c478bd9Sstevel@tonic-gate return (CAND_AVOID); 16147c478bd9Sstevel@tonic-gate } 16157c478bd9Sstevel@tonic-gate 16167c478bd9Sstevel@tonic-gate /* 1617e11c3f44Smeem * Prefer source addresses that are assigned to the outgoing interface. 16187c478bd9Sstevel@tonic-gate */ 1619f4b3ec61Sdh155122 /* ARGSUSED3 */ 16207c478bd9Sstevel@tonic-gate static rule_res_t 1621f4b3ec61Sdh155122 rule_interface(cand_t *bc, cand_t *cc, const dstinfo_t *dstinfo, 1622f4b3ec61Sdh155122 ip_stack_t *ipst) 16237c478bd9Sstevel@tonic-gate { 16247c478bd9Sstevel@tonic-gate ill_t *dstill = dstinfo->dst_ill; 16257c478bd9Sstevel@tonic-gate 16267c478bd9Sstevel@tonic-gate /* 16277c478bd9Sstevel@tonic-gate * If dstinfo->dst_restrict_ill is set, this rule is unnecessary 16287c478bd9Sstevel@tonic-gate * since we know all candidates will be on the same link. 16297c478bd9Sstevel@tonic-gate */ 16307c478bd9Sstevel@tonic-gate if (dstinfo->dst_restrict_ill) 16317c478bd9Sstevel@tonic-gate return (CAND_TIE); 16327c478bd9Sstevel@tonic-gate 16337c478bd9Sstevel@tonic-gate if (!bc->cand_matchedinterface_set) { 1634e11c3f44Smeem bc->cand_matchedinterface = bc->cand_ill == dstill; 16357c478bd9Sstevel@tonic-gate bc->cand_matchedinterface_set = B_TRUE; 16367c478bd9Sstevel@tonic-gate } 16377c478bd9Sstevel@tonic-gate 1638e11c3f44Smeem cc->cand_matchedinterface = cc->cand_ill == dstill; 16397c478bd9Sstevel@tonic-gate cc->cand_matchedinterface_set = B_TRUE; 16407c478bd9Sstevel@tonic-gate 16417c478bd9Sstevel@tonic-gate if (bc->cand_matchedinterface == cc->cand_matchedinterface) 16427c478bd9Sstevel@tonic-gate return (CAND_TIE); 16437c478bd9Sstevel@tonic-gate else if (cc->cand_matchedinterface) 16447c478bd9Sstevel@tonic-gate return (CAND_PREFER); 16457c478bd9Sstevel@tonic-gate else 16467c478bd9Sstevel@tonic-gate return (CAND_AVOID); 16477c478bd9Sstevel@tonic-gate } 16487c478bd9Sstevel@tonic-gate 16497c478bd9Sstevel@tonic-gate /* 16507c478bd9Sstevel@tonic-gate * Prefer source addresses whose label matches the destination's label. 16517c478bd9Sstevel@tonic-gate */ 16527c478bd9Sstevel@tonic-gate static rule_res_t 1653f4b3ec61Sdh155122 rule_label(cand_t *bc, cand_t *cc, const dstinfo_t *dstinfo, ip_stack_t *ipst) 16547c478bd9Sstevel@tonic-gate { 16557c478bd9Sstevel@tonic-gate char *label; 16567c478bd9Sstevel@tonic-gate 16577c478bd9Sstevel@tonic-gate if (!bc->cand_matchedlabel_set) { 1658f4b3ec61Sdh155122 label = ip6_asp_lookup(&bc->cand_srcaddr, NULL, ipst); 16597c478bd9Sstevel@tonic-gate bc->cand_matchedlabel = 16607c478bd9Sstevel@tonic-gate ip6_asp_labelcmp(label, dstinfo->dst_label); 16617c478bd9Sstevel@tonic-gate bc->cand_matchedlabel_set = B_TRUE; 16627c478bd9Sstevel@tonic-gate } 16637c478bd9Sstevel@tonic-gate 1664f4b3ec61Sdh155122 label = ip6_asp_lookup(&cc->cand_srcaddr, NULL, ipst); 16657c478bd9Sstevel@tonic-gate cc->cand_matchedlabel = ip6_asp_labelcmp(label, dstinfo->dst_label); 16667c478bd9Sstevel@tonic-gate cc->cand_matchedlabel_set = B_TRUE; 16677c478bd9Sstevel@tonic-gate 16687c478bd9Sstevel@tonic-gate if (bc->cand_matchedlabel == cc->cand_matchedlabel) 16697c478bd9Sstevel@tonic-gate return (CAND_TIE); 16707c478bd9Sstevel@tonic-gate else if (cc->cand_matchedlabel) 16717c478bd9Sstevel@tonic-gate return (CAND_PREFER); 16727c478bd9Sstevel@tonic-gate else 16737c478bd9Sstevel@tonic-gate return (CAND_AVOID); 16747c478bd9Sstevel@tonic-gate } 16757c478bd9Sstevel@tonic-gate 16767c478bd9Sstevel@tonic-gate /* 16777c478bd9Sstevel@tonic-gate * Prefer public addresses over temporary ones. An application can reverse 16787c478bd9Sstevel@tonic-gate * the logic of this rule and prefer temporary addresses by using the 16797c478bd9Sstevel@tonic-gate * IPV6_SRC_PREFERENCES socket option. 16807c478bd9Sstevel@tonic-gate */ 1681f4b3ec61Sdh155122 /* ARGSUSED3 */ 16827c478bd9Sstevel@tonic-gate static rule_res_t 1683f4b3ec61Sdh155122 rule_temporary(cand_t *bc, cand_t *cc, const dstinfo_t *dstinfo, 1684f4b3ec61Sdh155122 ip_stack_t *ipst) 16857c478bd9Sstevel@tonic-gate { 16867c478bd9Sstevel@tonic-gate if (!bc->cand_istmp_set) { 16877c478bd9Sstevel@tonic-gate bc->cand_istmp = ((bc->cand_flags & IPIF_TEMPORARY) != 0); 16887c478bd9Sstevel@tonic-gate bc->cand_istmp_set = B_TRUE; 16897c478bd9Sstevel@tonic-gate } 16907c478bd9Sstevel@tonic-gate 16917c478bd9Sstevel@tonic-gate cc->cand_istmp = ((cc->cand_flags & IPIF_TEMPORARY) != 0); 16927c478bd9Sstevel@tonic-gate cc->cand_istmp_set = B_TRUE; 16937c478bd9Sstevel@tonic-gate 16947c478bd9Sstevel@tonic-gate if (bc->cand_istmp == cc->cand_istmp) 16957c478bd9Sstevel@tonic-gate return (CAND_TIE); 16967c478bd9Sstevel@tonic-gate 16977c478bd9Sstevel@tonic-gate if (dstinfo->dst_prefer_src_tmp && cc->cand_istmp) 16987c478bd9Sstevel@tonic-gate return (CAND_PREFER); 16997c478bd9Sstevel@tonic-gate else if (!dstinfo->dst_prefer_src_tmp && !cc->cand_istmp) 17007c478bd9Sstevel@tonic-gate return (CAND_PREFER); 17017c478bd9Sstevel@tonic-gate else 17027c478bd9Sstevel@tonic-gate return (CAND_AVOID); 17037c478bd9Sstevel@tonic-gate } 17047c478bd9Sstevel@tonic-gate 17057c478bd9Sstevel@tonic-gate /* 1706d04ccbb3Scarlsonj * Prefer source addresses with longer matching prefix with the destination 1707d04ccbb3Scarlsonj * under the interface mask. This gets us on the same subnet before applying 1708d04ccbb3Scarlsonj * any Solaris-specific rules. 17097c478bd9Sstevel@tonic-gate */ 1710f4b3ec61Sdh155122 /* ARGSUSED3 */ 17117c478bd9Sstevel@tonic-gate static rule_res_t 1712f4b3ec61Sdh155122 rule_ifprefix(cand_t *bc, cand_t *cc, const dstinfo_t *dstinfo, 1713f4b3ec61Sdh155122 ip_stack_t *ipst) 17147c478bd9Sstevel@tonic-gate { 1715d04ccbb3Scarlsonj if (!bc->cand_pref_eq_set) { 1716d04ccbb3Scarlsonj bc->cand_pref_eq = V6_MASK_EQ_2(bc->cand_srcaddr, 1717d04ccbb3Scarlsonj bc->cand_mask, *dstinfo->dst_addr); 1718d04ccbb3Scarlsonj bc->cand_pref_eq_set = B_TRUE; 17197c478bd9Sstevel@tonic-gate } 17207c478bd9Sstevel@tonic-gate 1721d04ccbb3Scarlsonj cc->cand_pref_eq = V6_MASK_EQ_2(cc->cand_srcaddr, cc->cand_mask, 1722d04ccbb3Scarlsonj *dstinfo->dst_addr); 1723d04ccbb3Scarlsonj cc->cand_pref_eq_set = B_TRUE; 17247c478bd9Sstevel@tonic-gate 1725d04ccbb3Scarlsonj if (bc->cand_pref_eq) { 1726d04ccbb3Scarlsonj if (cc->cand_pref_eq) { 1727d04ccbb3Scarlsonj if (!bc->cand_pref_len_set) { 1728d04ccbb3Scarlsonj bc->cand_pref_len = 1729d04ccbb3Scarlsonj ip_mask_to_plen_v6(&bc->cand_mask); 1730d04ccbb3Scarlsonj bc->cand_pref_len_set = B_TRUE; 17317c478bd9Sstevel@tonic-gate } 1732d04ccbb3Scarlsonj cc->cand_pref_len = ip_mask_to_plen_v6(&cc->cand_mask); 1733d04ccbb3Scarlsonj cc->cand_pref_len_set = B_TRUE; 1734d04ccbb3Scarlsonj if (bc->cand_pref_len == cc->cand_pref_len) 1735d04ccbb3Scarlsonj return (CAND_TIE); 1736d04ccbb3Scarlsonj else if (bc->cand_pref_len > cc->cand_pref_len) 1737d04ccbb3Scarlsonj return (CAND_AVOID); 1738d04ccbb3Scarlsonj else 1739d04ccbb3Scarlsonj return (CAND_PREFER); 1740d04ccbb3Scarlsonj } else { 1741d04ccbb3Scarlsonj return (CAND_AVOID); 1742d04ccbb3Scarlsonj } 1743d04ccbb3Scarlsonj } else { 1744d04ccbb3Scarlsonj if (cc->cand_pref_eq) 17457c478bd9Sstevel@tonic-gate return (CAND_PREFER); 17467c478bd9Sstevel@tonic-gate else 1747d04ccbb3Scarlsonj return (CAND_TIE); 1748d04ccbb3Scarlsonj } 17497c478bd9Sstevel@tonic-gate } 17507c478bd9Sstevel@tonic-gate 17517c478bd9Sstevel@tonic-gate /* 175245916cd2Sjpk * Prefer to use zone-specific addresses when possible instead of all-zones 175345916cd2Sjpk * addresses. 175445916cd2Sjpk */ 175545916cd2Sjpk /* ARGSUSED2 */ 175645916cd2Sjpk static rule_res_t 1757f4b3ec61Sdh155122 rule_zone_specific(cand_t *bc, cand_t *cc, const dstinfo_t *dstinfo, 1758f4b3ec61Sdh155122 ip_stack_t *ipst) 175945916cd2Sjpk { 176045916cd2Sjpk if ((bc->cand_zoneid == ALL_ZONES) == 176145916cd2Sjpk (cc->cand_zoneid == ALL_ZONES)) 176245916cd2Sjpk return (CAND_TIE); 176345916cd2Sjpk else if (cc->cand_zoneid == ALL_ZONES) 176445916cd2Sjpk return (CAND_AVOID); 176545916cd2Sjpk else 176645916cd2Sjpk return (CAND_PREFER); 176745916cd2Sjpk } 176845916cd2Sjpk 176945916cd2Sjpk /* 1770d04ccbb3Scarlsonj * Prefer to use DHCPv6 (first) and static addresses (second) when possible 1771d04ccbb3Scarlsonj * instead of statelessly autoconfigured addresses. 1772d04ccbb3Scarlsonj * 1773d04ccbb3Scarlsonj * This is done after trying all other preferences (and before the final tie 1774d04ccbb3Scarlsonj * breaker) so that, if all else is equal, we select addresses configured by 1775d04ccbb3Scarlsonj * DHCPv6 over other addresses. We presume that DHCPv6 addresses, unlike 1776d04ccbb3Scarlsonj * stateless autoconfigured addresses, are deliberately configured by an 1777d04ccbb3Scarlsonj * administrator, and thus are correctly set up in DNS and network packet 1778d04ccbb3Scarlsonj * filters. 1779d04ccbb3Scarlsonj */ 1780d04ccbb3Scarlsonj /* ARGSUSED2 */ 1781d04ccbb3Scarlsonj static rule_res_t 1782f4b3ec61Sdh155122 rule_addr_type(cand_t *bc, cand_t *cc, const dstinfo_t *dstinfo, 1783f4b3ec61Sdh155122 ip_stack_t *ipst) 1784d04ccbb3Scarlsonj { 1785d04ccbb3Scarlsonj #define ATYPE(x) \ 1786d04ccbb3Scarlsonj ((x) & IPIF_DHCPRUNNING) ? 1 : ((x) & IPIF_ADDRCONF) ? 3 : 2 1787d04ccbb3Scarlsonj int bcval = ATYPE(bc->cand_flags); 1788d04ccbb3Scarlsonj int ccval = ATYPE(cc->cand_flags); 1789d04ccbb3Scarlsonj #undef ATYPE 1790d04ccbb3Scarlsonj 1791d04ccbb3Scarlsonj if (bcval == ccval) 1792d04ccbb3Scarlsonj return (CAND_TIE); 1793d04ccbb3Scarlsonj else if (ccval < bcval) 1794d04ccbb3Scarlsonj return (CAND_PREFER); 1795d04ccbb3Scarlsonj else 1796d04ccbb3Scarlsonj return (CAND_AVOID); 1797d04ccbb3Scarlsonj } 1798d04ccbb3Scarlsonj 1799d04ccbb3Scarlsonj /* 1800d04ccbb3Scarlsonj * Prefer source addresses with longer matching prefix with the destination. 1801d04ccbb3Scarlsonj * We do the longest matching prefix calculation by doing an xor of both 1802d04ccbb3Scarlsonj * addresses with the destination, and pick the address with the longest string 1803d04ccbb3Scarlsonj * of leading zeros, as per CommonPrefixLen() defined in RFC 3484. 1804d04ccbb3Scarlsonj */ 1805f4b3ec61Sdh155122 /* ARGSUSED3 */ 1806d04ccbb3Scarlsonj static rule_res_t 1807f4b3ec61Sdh155122 rule_prefix(cand_t *bc, cand_t *cc, const dstinfo_t *dstinfo, ip_stack_t *ipst) 1808d04ccbb3Scarlsonj { 1809d04ccbb3Scarlsonj if (!bc->cand_common_pref_set) { 1810d04ccbb3Scarlsonj bc->cand_common_pref = ip_common_prefix_v6(&bc->cand_srcaddr, 1811d04ccbb3Scarlsonj dstinfo->dst_addr); 1812d04ccbb3Scarlsonj bc->cand_common_pref_set = B_TRUE; 1813d04ccbb3Scarlsonj } 1814d04ccbb3Scarlsonj 1815d04ccbb3Scarlsonj cc->cand_common_pref = ip_common_prefix_v6(&cc->cand_srcaddr, 1816d04ccbb3Scarlsonj dstinfo->dst_addr); 1817d04ccbb3Scarlsonj cc->cand_common_pref_set = B_TRUE; 1818d04ccbb3Scarlsonj 1819d04ccbb3Scarlsonj if (bc->cand_common_pref == cc->cand_common_pref) 1820d04ccbb3Scarlsonj return (CAND_TIE); 1821d04ccbb3Scarlsonj else if (bc->cand_common_pref > cc->cand_common_pref) 1822d04ccbb3Scarlsonj return (CAND_AVOID); 1823d04ccbb3Scarlsonj else 1824d04ccbb3Scarlsonj return (CAND_PREFER); 1825d04ccbb3Scarlsonj } 1826d04ccbb3Scarlsonj 1827d04ccbb3Scarlsonj /* 1828d04ccbb3Scarlsonj * Last rule: we must pick something, so just prefer the current best 1829d04ccbb3Scarlsonj * candidate. 1830d04ccbb3Scarlsonj */ 1831d04ccbb3Scarlsonj /* ARGSUSED */ 1832d04ccbb3Scarlsonj static rule_res_t 1833f4b3ec61Sdh155122 rule_must_be_last(cand_t *bc, cand_t *cc, const dstinfo_t *dstinfo, 1834f4b3ec61Sdh155122 ip_stack_t *ipst) 1835d04ccbb3Scarlsonj { 1836d04ccbb3Scarlsonj return (CAND_AVOID); 1837d04ccbb3Scarlsonj } 1838d04ccbb3Scarlsonj 1839d04ccbb3Scarlsonj /* 18407c478bd9Sstevel@tonic-gate * Determine the best source address given a destination address and a 18417c478bd9Sstevel@tonic-gate * destination ill. If no suitable source address is found, it returns 18427c478bd9Sstevel@tonic-gate * NULL. If there is a usable address pointed to by the usesrc 18437c478bd9Sstevel@tonic-gate * (i.e ill_usesrc_ifindex != 0) then return that first since it is more 18447c478bd9Sstevel@tonic-gate * fine grained (i.e per interface) 18457c478bd9Sstevel@tonic-gate * 18467c478bd9Sstevel@tonic-gate * This implementation is based on the "Default Address Selection for IPv6" 18477c478bd9Sstevel@tonic-gate * specification produced by the IETF IPv6 working group. It has been 18487c478bd9Sstevel@tonic-gate * implemented so that the list of addresses is only traversed once (the 18497c478bd9Sstevel@tonic-gate * specification's algorithm could traverse the list of addresses once for 18507c478bd9Sstevel@tonic-gate * every rule). 18517c478bd9Sstevel@tonic-gate * 1852e11c3f44Smeem * The restrict_ill argument restricts the algorithm to choose a source 1853e11c3f44Smeem * address that is assigned to the destination ill. This is used when 1854e11c3f44Smeem * the destination address is a link-local or multicast address, and when 18557c478bd9Sstevel@tonic-gate * ipv6_strict_dst_multihoming is turned on. 18567c478bd9Sstevel@tonic-gate * 18577c478bd9Sstevel@tonic-gate * src_prefs is the caller's set of source address preferences. If source 18587c478bd9Sstevel@tonic-gate * address selection is being called to determine the source address of a 1859bd670b35SErik Nordmark * connected socket (from ip_set_destination_v6()), then the preferences are 1860bd670b35SErik Nordmark * taken from conn_ixa->ixa_src_preferences. These preferences can be set on a 18617c478bd9Sstevel@tonic-gate * per-socket basis using the IPV6_SRC_PREFERENCES socket option. The only 18627c478bd9Sstevel@tonic-gate * preference currently implemented is for rfc3041 temporary addresses. 18637c478bd9Sstevel@tonic-gate */ 18647c478bd9Sstevel@tonic-gate ipif_t * 18657c478bd9Sstevel@tonic-gate ipif_select_source_v6(ill_t *dstill, const in6_addr_t *dst, 1866bd670b35SErik Nordmark boolean_t restrict_ill, uint32_t src_prefs, zoneid_t zoneid, 1867bd670b35SErik Nordmark boolean_t allow_usesrc, boolean_t *notreadyp) 18687c478bd9Sstevel@tonic-gate { 18697c478bd9Sstevel@tonic-gate dstinfo_t dstinfo; 18707c478bd9Sstevel@tonic-gate char dstr[INET6_ADDRSTRLEN]; 18717c478bd9Sstevel@tonic-gate char sstr[INET6_ADDRSTRLEN]; 1872e11c3f44Smeem ipif_t *ipif, *start_ipif, *next_ipif; 1873e11c3f44Smeem ill_t *ill, *usesrc_ill = NULL, *ipmp_ill = NULL; 18747c478bd9Sstevel@tonic-gate ill_walk_context_t ctx; 18757c478bd9Sstevel@tonic-gate cand_t best_c; /* The best candidate */ 18767c478bd9Sstevel@tonic-gate cand_t curr_c; /* The current candidate */ 18777c478bd9Sstevel@tonic-gate uint_t index; 18787c478bd9Sstevel@tonic-gate boolean_t first_candidate = B_TRUE; 18797c478bd9Sstevel@tonic-gate rule_res_t rule_result; 188045916cd2Sjpk tsol_tpc_t *src_rhtp, *dst_rhtp; 1881f4b3ec61Sdh155122 ip_stack_t *ipst = dstill->ill_ipst; 18827c478bd9Sstevel@tonic-gate 18837c478bd9Sstevel@tonic-gate /* 18847c478bd9Sstevel@tonic-gate * The list of ordering rules. They are applied in the order they 18857c478bd9Sstevel@tonic-gate * appear in the list. 18867c478bd9Sstevel@tonic-gate * 1887d04ccbb3Scarlsonj * Solaris doesn't currently support Mobile IPv6, so there's no 1888d04ccbb3Scarlsonj * rule_mipv6 corresponding to rule 4 in the specification. 18897c478bd9Sstevel@tonic-gate */ 18907c478bd9Sstevel@tonic-gate rulef_t rules[] = { 18917c478bd9Sstevel@tonic-gate rule_isdst, 18927c478bd9Sstevel@tonic-gate rule_scope, 18937c478bd9Sstevel@tonic-gate rule_deprecated, 18947c478bd9Sstevel@tonic-gate rule_preferred, 18957c478bd9Sstevel@tonic-gate rule_interface, 18967c478bd9Sstevel@tonic-gate rule_label, 18977c478bd9Sstevel@tonic-gate rule_temporary, 1898d04ccbb3Scarlsonj rule_ifprefix, /* local rules after this */ 189945916cd2Sjpk rule_zone_specific, 1900d04ccbb3Scarlsonj rule_addr_type, 1901d04ccbb3Scarlsonj rule_prefix, /* local rules before this */ 1902d04ccbb3Scarlsonj rule_must_be_last, /* must always be last */ 19037c478bd9Sstevel@tonic-gate NULL 19047c478bd9Sstevel@tonic-gate }; 19057c478bd9Sstevel@tonic-gate 19067c478bd9Sstevel@tonic-gate ASSERT(dstill->ill_isv6); 19077c478bd9Sstevel@tonic-gate ASSERT(!IN6_IS_ADDR_V4MAPPED(dst)); 19087c478bd9Sstevel@tonic-gate 19097c478bd9Sstevel@tonic-gate /* 19107c478bd9Sstevel@tonic-gate * Check if there is a usable src address pointed to by the 19117c478bd9Sstevel@tonic-gate * usesrc ifindex. This has higher precedence since it is 19127c478bd9Sstevel@tonic-gate * finer grained (i.e per interface) v/s being system wide. 19137c478bd9Sstevel@tonic-gate */ 1914bd670b35SErik Nordmark if (dstill->ill_usesrc_ifindex != 0 && allow_usesrc) { 19157c478bd9Sstevel@tonic-gate if ((usesrc_ill = 19167c478bd9Sstevel@tonic-gate ill_lookup_on_ifindex(dstill->ill_usesrc_ifindex, B_TRUE, 1917bd670b35SErik Nordmark ipst)) != NULL) { 19187c478bd9Sstevel@tonic-gate dstinfo.dst_ill = usesrc_ill; 19197c478bd9Sstevel@tonic-gate } else { 19207c478bd9Sstevel@tonic-gate return (NULL); 19217c478bd9Sstevel@tonic-gate } 1922e11c3f44Smeem } else if (IS_UNDER_IPMP(dstill)) { 1923e11c3f44Smeem /* 1924e11c3f44Smeem * Test addresses should never be used for source address 1925e11c3f44Smeem * selection, so if we were passed an underlying ill, switch 1926e11c3f44Smeem * to the IPMP meta-interface. 1927e11c3f44Smeem */ 1928e11c3f44Smeem if ((ipmp_ill = ipmp_ill_hold_ipmp_ill(dstill)) != NULL) 1929e11c3f44Smeem dstinfo.dst_ill = ipmp_ill; 1930e11c3f44Smeem else 1931e11c3f44Smeem return (NULL); 19327c478bd9Sstevel@tonic-gate } else { 19337c478bd9Sstevel@tonic-gate dstinfo.dst_ill = dstill; 19347c478bd9Sstevel@tonic-gate } 19357c478bd9Sstevel@tonic-gate 193645916cd2Sjpk /* 193745916cd2Sjpk * If we're dealing with an unlabeled destination on a labeled system, 193845916cd2Sjpk * make sure that we ignore source addresses that are incompatible with 193945916cd2Sjpk * the destination's default label. That destination's default label 194045916cd2Sjpk * must dominate the minimum label on the source address. 194145916cd2Sjpk * 194245916cd2Sjpk * (Note that this has to do with Trusted Solaris. It's not related to 194345916cd2Sjpk * the labels described by ip6_asp_lookup.) 194445916cd2Sjpk */ 194545916cd2Sjpk dst_rhtp = NULL; 194645916cd2Sjpk if (is_system_labeled()) { 194745916cd2Sjpk dst_rhtp = find_tpc(dst, IPV6_VERSION, B_FALSE); 194845916cd2Sjpk if (dst_rhtp == NULL) 194945916cd2Sjpk return (NULL); 195045916cd2Sjpk if (dst_rhtp->tpc_tp.host_type != UNLABELED) { 195145916cd2Sjpk TPC_RELE(dst_rhtp); 195245916cd2Sjpk dst_rhtp = NULL; 195345916cd2Sjpk } 195445916cd2Sjpk } 195545916cd2Sjpk 19567c478bd9Sstevel@tonic-gate dstinfo.dst_addr = dst; 19577c478bd9Sstevel@tonic-gate dstinfo.dst_scope = ip_addr_scope_v6(dst); 1958f4b3ec61Sdh155122 dstinfo.dst_label = ip6_asp_lookup(dst, NULL, ipst); 19597c478bd9Sstevel@tonic-gate dstinfo.dst_prefer_src_tmp = ((src_prefs & IPV6_PREFER_SRC_TMP) != 0); 1960f4b3ec61Sdh155122 rw_enter(&ipst->ips_ill_g_lock, RW_READER); 19617c478bd9Sstevel@tonic-gate /* 19627c478bd9Sstevel@tonic-gate * Section three of the I-D states that for multicast and 19637c478bd9Sstevel@tonic-gate * link-local destinations, the candidate set must be restricted to 19647c478bd9Sstevel@tonic-gate * an interface that is on the same link as the outgoing interface. 19657c478bd9Sstevel@tonic-gate * Also, when ipv6_strict_dst_multihoming is turned on, always 19667c478bd9Sstevel@tonic-gate * restrict the source address to the destination link as doing 19677c478bd9Sstevel@tonic-gate * otherwise will almost certainly cause problems. 19687c478bd9Sstevel@tonic-gate */ 19697c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_LINKLOCAL(dst) || IN6_IS_ADDR_MULTICAST(dst) || 1970f4b3ec61Sdh155122 ipst->ips_ipv6_strict_dst_multihoming || usesrc_ill != NULL) { 1971e11c3f44Smeem dstinfo.dst_restrict_ill = B_TRUE; 1972309fa174Srk129064 } else { 1973309fa174Srk129064 dstinfo.dst_restrict_ill = restrict_ill; 1974309fa174Srk129064 } 19757c478bd9Sstevel@tonic-gate 19767c478bd9Sstevel@tonic-gate bzero(&best_c, sizeof (cand_t)); 19777c478bd9Sstevel@tonic-gate 19787c478bd9Sstevel@tonic-gate /* 1979e11c3f44Smeem * Take a pass through the list of IPv6 interfaces to choose the best 1980e11c3f44Smeem * possible source address. If restrict_ill is set, just use dst_ill. 19817c478bd9Sstevel@tonic-gate */ 1982e11c3f44Smeem if (dstinfo.dst_restrict_ill) 19837c478bd9Sstevel@tonic-gate ill = dstinfo.dst_ill; 1984e11c3f44Smeem else 1985f4b3ec61Sdh155122 ill = ILL_START_WALK_V6(&ctx, ipst); 19867c478bd9Sstevel@tonic-gate 1987e11c3f44Smeem for (; ill != NULL; ill = ill_next(&ctx, ill)) { 19887c478bd9Sstevel@tonic-gate ASSERT(ill->ill_isv6); 19897c478bd9Sstevel@tonic-gate 1990309fa174Srk129064 /* 1991e11c3f44Smeem * Test addresses should never be used for source address 1992e11c3f44Smeem * selection, so ignore underlying ills. 1993309fa174Srk129064 */ 1994e11c3f44Smeem if (IS_UNDER_IPMP(ill)) 1995e11c3f44Smeem continue; 1996309fa174Srk129064 1997ee07f6e7SSowmini Varadhan if (ill->ill_ipif == NULL) 1998ee07f6e7SSowmini Varadhan continue; 1999e11c3f44Smeem /* 2000e11c3f44Smeem * For source address selection, we treat the ipif list as 2001e11c3f44Smeem * circular and continue until we get back to where we 2002e11c3f44Smeem * started. This allows IPMP to vary source address selection 2003e11c3f44Smeem * (which improves inbound load spreading) by caching its last 2004e11c3f44Smeem * ending point and starting from there. NOTE: we don't have 2005e11c3f44Smeem * to worry about ill_src_ipif changing ills since that can't 2006e11c3f44Smeem * happen on the IPMP ill. 2007e11c3f44Smeem */ 2008e11c3f44Smeem start_ipif = ill->ill_ipif; 2009e11c3f44Smeem if (IS_IPMP(ill) && ill->ill_src_ipif != NULL) 2010e11c3f44Smeem start_ipif = ill->ill_src_ipif; 2011e11c3f44Smeem 2012e11c3f44Smeem ipif = start_ipif; 2013e11c3f44Smeem do { 2014e11c3f44Smeem if ((next_ipif = ipif->ipif_next) == NULL) 2015e11c3f44Smeem next_ipif = ill->ill_ipif; 20167c478bd9Sstevel@tonic-gate 20177c478bd9Sstevel@tonic-gate if (!IPIF_VALID_IPV6_SOURCE(ipif)) 20187c478bd9Sstevel@tonic-gate continue; 20197c478bd9Sstevel@tonic-gate 2020bd670b35SErik Nordmark if (!ipif->ipif_addr_ready) { 2021bd670b35SErik Nordmark if (notreadyp != NULL) 2022bd670b35SErik Nordmark *notreadyp = B_TRUE; 2023bd670b35SErik Nordmark continue; 2024bd670b35SErik Nordmark } 2025bd670b35SErik Nordmark 202645916cd2Sjpk if (zoneid != ALL_ZONES && 202745916cd2Sjpk ipif->ipif_zoneid != zoneid && 202845916cd2Sjpk ipif->ipif_zoneid != ALL_ZONES) 20297c478bd9Sstevel@tonic-gate continue; 20307c478bd9Sstevel@tonic-gate 203145916cd2Sjpk /* 203245916cd2Sjpk * Check compatibility of local address for 203345916cd2Sjpk * destination's default label if we're on a labeled 203445916cd2Sjpk * system. Incompatible addresses can't be used at 203545916cd2Sjpk * all and must be skipped over. 203645916cd2Sjpk */ 203745916cd2Sjpk if (dst_rhtp != NULL) { 203845916cd2Sjpk boolean_t incompat; 203945916cd2Sjpk 204045916cd2Sjpk src_rhtp = find_tpc(&ipif->ipif_v6lcl_addr, 204145916cd2Sjpk IPV6_VERSION, B_FALSE); 204245916cd2Sjpk if (src_rhtp == NULL) 204345916cd2Sjpk continue; 204445916cd2Sjpk incompat = 204545916cd2Sjpk src_rhtp->tpc_tp.host_type != SUN_CIPSO || 204645916cd2Sjpk src_rhtp->tpc_tp.tp_doi != 204745916cd2Sjpk dst_rhtp->tpc_tp.tp_doi || 204845916cd2Sjpk (!_blinrange(&dst_rhtp->tpc_tp.tp_def_label, 204945916cd2Sjpk &src_rhtp->tpc_tp.tp_sl_range_cipso) && 205045916cd2Sjpk !blinlset(&dst_rhtp->tpc_tp.tp_def_label, 205145916cd2Sjpk src_rhtp->tpc_tp.tp_sl_set_cipso)); 205245916cd2Sjpk TPC_RELE(src_rhtp); 205345916cd2Sjpk if (incompat) 205445916cd2Sjpk continue; 205545916cd2Sjpk } 205645916cd2Sjpk 20577c478bd9Sstevel@tonic-gate if (first_candidate) { 20587c478bd9Sstevel@tonic-gate /* 20597c478bd9Sstevel@tonic-gate * This is first valid address in the list. 20607c478bd9Sstevel@tonic-gate * It is automatically the best candidate 20617c478bd9Sstevel@tonic-gate * so far. 20627c478bd9Sstevel@tonic-gate */ 20637c478bd9Sstevel@tonic-gate best_c.cand_ipif = ipif; 20647c478bd9Sstevel@tonic-gate first_candidate = B_FALSE; 20657c478bd9Sstevel@tonic-gate continue; 20667c478bd9Sstevel@tonic-gate } 20677c478bd9Sstevel@tonic-gate 20687c478bd9Sstevel@tonic-gate bzero(&curr_c, sizeof (cand_t)); 20697c478bd9Sstevel@tonic-gate curr_c.cand_ipif = ipif; 20707c478bd9Sstevel@tonic-gate 20717c478bd9Sstevel@tonic-gate /* 20727c478bd9Sstevel@tonic-gate * Compare this current candidate (curr_c) with the 20737c478bd9Sstevel@tonic-gate * best candidate (best_c) by applying the 20747c478bd9Sstevel@tonic-gate * comparison rules in order until one breaks the 20757c478bd9Sstevel@tonic-gate * tie. 20767c478bd9Sstevel@tonic-gate */ 20777c478bd9Sstevel@tonic-gate for (index = 0; rules[index] != NULL; index++) { 20787c478bd9Sstevel@tonic-gate /* Apply a comparison rule. */ 2079e11c3f44Smeem rule_result = (rules[index])(&best_c, &curr_c, 2080e11c3f44Smeem &dstinfo, ipst); 20817c478bd9Sstevel@tonic-gate if (rule_result == CAND_AVOID) { 20827c478bd9Sstevel@tonic-gate /* 20837c478bd9Sstevel@tonic-gate * The best candidate is still the 20847c478bd9Sstevel@tonic-gate * best candidate. Forget about 20857c478bd9Sstevel@tonic-gate * this current candidate and go on 20867c478bd9Sstevel@tonic-gate * to the next one. 20877c478bd9Sstevel@tonic-gate */ 20887c478bd9Sstevel@tonic-gate break; 20897c478bd9Sstevel@tonic-gate } else if (rule_result == CAND_PREFER) { 20907c478bd9Sstevel@tonic-gate /* 20917c478bd9Sstevel@tonic-gate * This candidate is prefered. It 20927c478bd9Sstevel@tonic-gate * becomes the best candidate so 20937c478bd9Sstevel@tonic-gate * far. Go on to the next address. 20947c478bd9Sstevel@tonic-gate */ 20957c478bd9Sstevel@tonic-gate best_c = curr_c; 20967c478bd9Sstevel@tonic-gate break; 20977c478bd9Sstevel@tonic-gate } 20987c478bd9Sstevel@tonic-gate /* We have a tie, apply the next rule. */ 20997c478bd9Sstevel@tonic-gate } 21007c478bd9Sstevel@tonic-gate 21017c478bd9Sstevel@tonic-gate /* 21027c478bd9Sstevel@tonic-gate * The last rule must be a tie breaker rule and 21037c478bd9Sstevel@tonic-gate * must never produce a tie. At this point, the 21047c478bd9Sstevel@tonic-gate * candidate should have either been rejected, or 21057c478bd9Sstevel@tonic-gate * have been prefered as the best candidate so far. 21067c478bd9Sstevel@tonic-gate */ 21077c478bd9Sstevel@tonic-gate ASSERT(rule_result != CAND_TIE); 2108e11c3f44Smeem } while ((ipif = next_ipif) != start_ipif); 2109e11c3f44Smeem 2110e11c3f44Smeem /* 2111e11c3f44Smeem * For IPMP, update the source ipif rotor to the next ipif, 2112e11c3f44Smeem * provided we can look it up. (We must not use it if it's 2113e11c3f44Smeem * IPIF_CONDEMNED since we may have grabbed ill_g_lock after 2114e11c3f44Smeem * ipif_free() checked ill_src_ipif.) 2115e11c3f44Smeem */ 2116e11c3f44Smeem if (IS_IPMP(ill) && ipif != NULL) { 2117e11c3f44Smeem mutex_enter(&ipif->ipif_ill->ill_lock); 2118e11c3f44Smeem next_ipif = ipif->ipif_next; 2119bd670b35SErik Nordmark if (next_ipif != NULL && !IPIF_IS_CONDEMNED(next_ipif)) 2120e11c3f44Smeem ill->ill_src_ipif = next_ipif; 2121e11c3f44Smeem else 2122e11c3f44Smeem ill->ill_src_ipif = NULL; 2123e11c3f44Smeem mutex_exit(&ipif->ipif_ill->ill_lock); 21247c478bd9Sstevel@tonic-gate } 21257c478bd9Sstevel@tonic-gate 21267c478bd9Sstevel@tonic-gate /* 2127e11c3f44Smeem * Only one ill to consider if dst_restrict_ill is set. 21287c478bd9Sstevel@tonic-gate */ 2129e11c3f44Smeem if (dstinfo.dst_restrict_ill) 2130e11c3f44Smeem break; 21317c478bd9Sstevel@tonic-gate } 21327c478bd9Sstevel@tonic-gate 21337c478bd9Sstevel@tonic-gate ipif = best_c.cand_ipif; 21347c478bd9Sstevel@tonic-gate ip1dbg(("ipif_select_source_v6(%s, %s) -> %s\n", 21357c478bd9Sstevel@tonic-gate dstinfo.dst_ill->ill_name, 21367c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, dstinfo.dst_addr, dstr, sizeof (dstr)), 21377c478bd9Sstevel@tonic-gate (ipif == NULL ? "NULL" : 21387c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, &ipif->ipif_v6lcl_addr, sstr, sizeof (sstr))))); 21397c478bd9Sstevel@tonic-gate 21407c478bd9Sstevel@tonic-gate if (usesrc_ill != NULL) 21417c478bd9Sstevel@tonic-gate ill_refrele(usesrc_ill); 21427c478bd9Sstevel@tonic-gate 2143e11c3f44Smeem if (ipmp_ill != NULL) 2144e11c3f44Smeem ill_refrele(ipmp_ill); 2145e11c3f44Smeem 214645916cd2Sjpk if (dst_rhtp != NULL) 214745916cd2Sjpk TPC_RELE(dst_rhtp); 214845916cd2Sjpk 21497c478bd9Sstevel@tonic-gate if (ipif == NULL) { 2150f4b3ec61Sdh155122 rw_exit(&ipst->ips_ill_g_lock); 21517c478bd9Sstevel@tonic-gate return (NULL); 21527c478bd9Sstevel@tonic-gate } 21537c478bd9Sstevel@tonic-gate 21547c478bd9Sstevel@tonic-gate mutex_enter(&ipif->ipif_ill->ill_lock); 2155bd670b35SErik Nordmark if (!IPIF_IS_CONDEMNED(ipif)) { 21567c478bd9Sstevel@tonic-gate ipif_refhold_locked(ipif); 21577c478bd9Sstevel@tonic-gate mutex_exit(&ipif->ipif_ill->ill_lock); 2158f4b3ec61Sdh155122 rw_exit(&ipst->ips_ill_g_lock); 21597c478bd9Sstevel@tonic-gate return (ipif); 21607c478bd9Sstevel@tonic-gate } 21617c478bd9Sstevel@tonic-gate mutex_exit(&ipif->ipif_ill->ill_lock); 2162f4b3ec61Sdh155122 rw_exit(&ipst->ips_ill_g_lock); 21637c478bd9Sstevel@tonic-gate ip1dbg(("ipif_select_source_v6 cannot lookup ipif %p" 21647c478bd9Sstevel@tonic-gate " returning null \n", (void *)ipif)); 21657c478bd9Sstevel@tonic-gate 21667c478bd9Sstevel@tonic-gate return (NULL); 21677c478bd9Sstevel@tonic-gate } 21687c478bd9Sstevel@tonic-gate 21697c478bd9Sstevel@tonic-gate /* 2170bd670b35SErik Nordmark * Pick a source address based on the destination ill and an optional setsrc 2171bd670b35SErik Nordmark * address. 2172bd670b35SErik Nordmark * The result is stored in srcp. If generation is set, then put the source 2173bd670b35SErik Nordmark * generation number there before we look for the source address (to avoid 2174bd670b35SErik Nordmark * missing changes in the set of source addresses. 2175bd670b35SErik Nordmark * If flagsp is set, then us it to pass back ipif_flags. 21767c478bd9Sstevel@tonic-gate * 2177bd670b35SErik Nordmark * If the caller wants to cache the returned source address and detect when 2178bd670b35SErik Nordmark * that might be stale, the caller should pass in a generation argument, 2179bd670b35SErik Nordmark * which the caller can later compare against ips_src_generation 21807c478bd9Sstevel@tonic-gate * 2181bd670b35SErik Nordmark * The precedence order for selecting an IPv6 source address is: 2182bd670b35SErik Nordmark * - RTF_SETSRC on the first ire in the recursive lookup always wins. 2183bd670b35SErik Nordmark * - If usrsrc is set, swap the ill to be the usesrc one. 2184bd670b35SErik Nordmark * - If IPMP is used on the ill, select a random address from the most 2185bd670b35SErik Nordmark * preferred ones below: 2186bd670b35SErik Nordmark * That is followed by the long list of IPv6 source address selection rules 2187bd670b35SErik Nordmark * starting with rule_isdst(), rule_scope(), etc. 2188bd670b35SErik Nordmark * 2189bd670b35SErik Nordmark * We have lower preference for ALL_ZONES IP addresses, 2190bd670b35SErik Nordmark * as they pose problems with unlabeled destinations. 2191bd670b35SErik Nordmark * 2192bd670b35SErik Nordmark * Note that when multiple IP addresses match e.g., with rule_scope() we pick 2193bd670b35SErik Nordmark * the first one if IPMP is not in use. With IPMP we randomize. 21947c478bd9Sstevel@tonic-gate */ 2195bd670b35SErik Nordmark int 2196bd670b35SErik Nordmark ip_select_source_v6(ill_t *ill, const in6_addr_t *setsrc, const in6_addr_t *dst, 2197bd670b35SErik Nordmark zoneid_t zoneid, ip_stack_t *ipst, uint_t restrict_ill, uint32_t src_prefs, 2198bd670b35SErik Nordmark in6_addr_t *srcp, uint32_t *generation, uint64_t *flagsp) 21997c478bd9Sstevel@tonic-gate { 22007c478bd9Sstevel@tonic-gate ipif_t *ipif; 2201bd670b35SErik Nordmark boolean_t notready = B_FALSE; /* Set if !ipif_addr_ready found */ 22027c478bd9Sstevel@tonic-gate 2203bd670b35SErik Nordmark if (flagsp != NULL) 2204bd670b35SErik Nordmark *flagsp = 0; 22057c478bd9Sstevel@tonic-gate 2206bd670b35SErik Nordmark /* 2207bd670b35SErik Nordmark * Need to grab the generation number before we check to 2208bd670b35SErik Nordmark * avoid a race with a change to the set of local addresses. 2209bd670b35SErik Nordmark * No lock needed since the thread which updates the set of local 2210bd670b35SErik Nordmark * addresses use ipif/ill locks and exit those (hence a store memory 2211bd670b35SErik Nordmark * barrier) before doing the atomic increase of ips_src_generation. 2212bd670b35SErik Nordmark */ 2213bd670b35SErik Nordmark if (generation != NULL) { 2214bd670b35SErik Nordmark *generation = ipst->ips_src_generation; 22157c478bd9Sstevel@tonic-gate } 2216bd670b35SErik Nordmark 2217bd670b35SErik Nordmark /* Was RTF_SETSRC set on the first IRE in the recursive lookup? */ 2218bd670b35SErik Nordmark if (setsrc != NULL && !IN6_IS_ADDR_UNSPECIFIED(setsrc)) { 2219bd670b35SErik Nordmark *srcp = *setsrc; 2220bd670b35SErik Nordmark return (0); 2221bd670b35SErik Nordmark } 2222bd670b35SErik Nordmark 2223bd670b35SErik Nordmark ipif = ipif_select_source_v6(ill, dst, restrict_ill, src_prefs, zoneid, 2224bd670b35SErik Nordmark B_TRUE, ¬ready); 2225bd670b35SErik Nordmark if (ipif == NULL) { 2226bd670b35SErik Nordmark if (notready) 2227bd670b35SErik Nordmark return (ENETDOWN); 2228bd670b35SErik Nordmark else 2229bd670b35SErik Nordmark return (EADDRNOTAVAIL); 2230bd670b35SErik Nordmark } 2231bd670b35SErik Nordmark *srcp = ipif->ipif_v6lcl_addr; 2232bd670b35SErik Nordmark if (flagsp != NULL) 2233bd670b35SErik Nordmark *flagsp = ipif->ipif_flags; 2234bd670b35SErik Nordmark ipif_refrele(ipif); 2235bd670b35SErik Nordmark return (0); 22367c478bd9Sstevel@tonic-gate } 22377c478bd9Sstevel@tonic-gate 22387c478bd9Sstevel@tonic-gate /* 22397c478bd9Sstevel@tonic-gate * Perform an attach and bind to get phys addr plus info_req for 22407c478bd9Sstevel@tonic-gate * the physical device. 22417c478bd9Sstevel@tonic-gate * q and mp represents an ioctl which will be queued waiting for 22427c478bd9Sstevel@tonic-gate * completion of the DLPI message exchange. 2243bd670b35SErik Nordmark * MUST be called on an ill queue. 22447c478bd9Sstevel@tonic-gate * 2245bd670b35SErik Nordmark * Returns EINPROGRESS when mp has been consumed by queueing it. 2246bd670b35SErik Nordmark * The ioctl will complete in ip_rput. 22477c478bd9Sstevel@tonic-gate */ 22487c478bd9Sstevel@tonic-gate int 22497c478bd9Sstevel@tonic-gate ill_dl_phys(ill_t *ill, ipif_t *ipif, mblk_t *mp, queue_t *q) 22507c478bd9Sstevel@tonic-gate { 22517c478bd9Sstevel@tonic-gate mblk_t *v6token_mp = NULL; 22527c478bd9Sstevel@tonic-gate mblk_t *v6lla_mp = NULL; 22532b24ab6bSSebastien Roy mblk_t *dest_mp = NULL; 22547c478bd9Sstevel@tonic-gate mblk_t *phys_mp = NULL; 22557c478bd9Sstevel@tonic-gate mblk_t *info_mp = NULL; 22567c478bd9Sstevel@tonic-gate mblk_t *attach_mp = NULL; 22577c478bd9Sstevel@tonic-gate mblk_t *bind_mp = NULL; 22587c478bd9Sstevel@tonic-gate mblk_t *unbind_mp = NULL; 22597c478bd9Sstevel@tonic-gate mblk_t *notify_mp = NULL; 22601cb875aeSCathy Zhou mblk_t *capab_mp = NULL; 22617c478bd9Sstevel@tonic-gate 22627c478bd9Sstevel@tonic-gate ip1dbg(("ill_dl_phys(%s:%u)\n", ill->ill_name, ipif->ipif_id)); 22637c478bd9Sstevel@tonic-gate ASSERT(ill->ill_dlpi_style_set); 22647c478bd9Sstevel@tonic-gate ASSERT(WR(q)->q_next != NULL); 22657c478bd9Sstevel@tonic-gate 22667c478bd9Sstevel@tonic-gate if (ill->ill_isv6) { 22677c478bd9Sstevel@tonic-gate v6token_mp = ip_dlpi_alloc(sizeof (dl_phys_addr_req_t) + 22687c478bd9Sstevel@tonic-gate sizeof (t_scalar_t), DL_PHYS_ADDR_REQ); 22697c478bd9Sstevel@tonic-gate if (v6token_mp == NULL) 22707c478bd9Sstevel@tonic-gate goto bad; 22717c478bd9Sstevel@tonic-gate ((dl_phys_addr_req_t *)v6token_mp->b_rptr)->dl_addr_type = 22727c478bd9Sstevel@tonic-gate DL_IPV6_TOKEN; 22737c478bd9Sstevel@tonic-gate 22747c478bd9Sstevel@tonic-gate v6lla_mp = ip_dlpi_alloc(sizeof (dl_phys_addr_req_t) + 22757c478bd9Sstevel@tonic-gate sizeof (t_scalar_t), DL_PHYS_ADDR_REQ); 22767c478bd9Sstevel@tonic-gate if (v6lla_mp == NULL) 22777c478bd9Sstevel@tonic-gate goto bad; 22787c478bd9Sstevel@tonic-gate ((dl_phys_addr_req_t *)v6lla_mp->b_rptr)->dl_addr_type = 22797c478bd9Sstevel@tonic-gate DL_IPV6_LINK_LAYER_ADDR; 22807c478bd9Sstevel@tonic-gate } 22817c478bd9Sstevel@tonic-gate 22822b24ab6bSSebastien Roy if (ill->ill_mactype == DL_IPV4 || ill->ill_mactype == DL_IPV6) { 22832b24ab6bSSebastien Roy dest_mp = ip_dlpi_alloc(sizeof (dl_phys_addr_req_t) + 22842b24ab6bSSebastien Roy sizeof (t_scalar_t), DL_PHYS_ADDR_REQ); 22852b24ab6bSSebastien Roy if (dest_mp == NULL) 22862b24ab6bSSebastien Roy goto bad; 22872b24ab6bSSebastien Roy ((dl_phys_addr_req_t *)dest_mp->b_rptr)->dl_addr_type = 22882b24ab6bSSebastien Roy DL_CURR_DEST_ADDR; 22892b24ab6bSSebastien Roy } 22902b24ab6bSSebastien Roy 22917c478bd9Sstevel@tonic-gate /* 22927c478bd9Sstevel@tonic-gate * Allocate a DL_NOTIFY_REQ and set the notifications we want. 22937c478bd9Sstevel@tonic-gate */ 22947c478bd9Sstevel@tonic-gate notify_mp = ip_dlpi_alloc(sizeof (dl_notify_req_t) + sizeof (long), 22957c478bd9Sstevel@tonic-gate DL_NOTIFY_REQ); 22967c478bd9Sstevel@tonic-gate if (notify_mp == NULL) 22977c478bd9Sstevel@tonic-gate goto bad; 22987c478bd9Sstevel@tonic-gate ((dl_notify_req_t *)notify_mp->b_rptr)->dl_notifications = 22997c478bd9Sstevel@tonic-gate (DL_NOTE_PHYS_ADDR | DL_NOTE_SDU_SIZE | DL_NOTE_FASTPATH_FLUSH | 23005d460eafSCathy Zhou DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN | DL_NOTE_CAPAB_RENEG | 2301806139abSGirish Moodalbail DL_NOTE_PROMISC_ON_PHYS | DL_NOTE_PROMISC_OFF_PHYS | 2302*1eee170aSErik Nordmark DL_NOTE_REPLUMB | DL_NOTE_ALLOWED_IPS | DL_NOTE_SDU_SIZE2); 23037c478bd9Sstevel@tonic-gate 23047c478bd9Sstevel@tonic-gate phys_mp = ip_dlpi_alloc(sizeof (dl_phys_addr_req_t) + 23057c478bd9Sstevel@tonic-gate sizeof (t_scalar_t), DL_PHYS_ADDR_REQ); 23067c478bd9Sstevel@tonic-gate if (phys_mp == NULL) 23077c478bd9Sstevel@tonic-gate goto bad; 23087c478bd9Sstevel@tonic-gate ((dl_phys_addr_req_t *)phys_mp->b_rptr)->dl_addr_type = 23097c478bd9Sstevel@tonic-gate DL_CURR_PHYS_ADDR; 23107c478bd9Sstevel@tonic-gate 23117c478bd9Sstevel@tonic-gate info_mp = ip_dlpi_alloc( 23127c478bd9Sstevel@tonic-gate sizeof (dl_info_req_t) + sizeof (dl_info_ack_t), 23137c478bd9Sstevel@tonic-gate DL_INFO_REQ); 23147c478bd9Sstevel@tonic-gate if (info_mp == NULL) 23157c478bd9Sstevel@tonic-gate goto bad; 23167c478bd9Sstevel@tonic-gate 23171cb875aeSCathy Zhou ASSERT(ill->ill_dlpi_capab_state == IDCS_UNKNOWN); 23181cb875aeSCathy Zhou capab_mp = ip_dlpi_alloc(sizeof (dl_capability_req_t), 23191cb875aeSCathy Zhou DL_CAPABILITY_REQ); 23201cb875aeSCathy Zhou if (capab_mp == NULL) 23211cb875aeSCathy Zhou goto bad; 23221cb875aeSCathy Zhou 23237c478bd9Sstevel@tonic-gate bind_mp = ip_dlpi_alloc(sizeof (dl_bind_req_t) + sizeof (long), 23247c478bd9Sstevel@tonic-gate DL_BIND_REQ); 23257c478bd9Sstevel@tonic-gate if (bind_mp == NULL) 23267c478bd9Sstevel@tonic-gate goto bad; 23277c478bd9Sstevel@tonic-gate ((dl_bind_req_t *)bind_mp->b_rptr)->dl_sap = ill->ill_sap; 23287c478bd9Sstevel@tonic-gate ((dl_bind_req_t *)bind_mp->b_rptr)->dl_service_mode = DL_CLDLS; 23297c478bd9Sstevel@tonic-gate 23307c478bd9Sstevel@tonic-gate unbind_mp = ip_dlpi_alloc(sizeof (dl_unbind_req_t), DL_UNBIND_REQ); 23317c478bd9Sstevel@tonic-gate if (unbind_mp == NULL) 23327c478bd9Sstevel@tonic-gate goto bad; 23337c478bd9Sstevel@tonic-gate 23348df01f76Smeem /* If we need to attach, pre-alloc and initialize the mblk */ 23357c478bd9Sstevel@tonic-gate if (ill->ill_needs_attach) { 23367c478bd9Sstevel@tonic-gate attach_mp = ip_dlpi_alloc(sizeof (dl_attach_req_t), 23377c478bd9Sstevel@tonic-gate DL_ATTACH_REQ); 23387c478bd9Sstevel@tonic-gate if (attach_mp == NULL) 23397c478bd9Sstevel@tonic-gate goto bad; 23407c478bd9Sstevel@tonic-gate ((dl_attach_req_t *)attach_mp->b_rptr)->dl_ppa = ill->ill_ppa; 23417c478bd9Sstevel@tonic-gate } 23427c478bd9Sstevel@tonic-gate 23437c478bd9Sstevel@tonic-gate /* 23447c478bd9Sstevel@tonic-gate * Here we are going to delay the ioctl ack until after 23457c478bd9Sstevel@tonic-gate * ACKs from DL_PHYS_ADDR_REQ. So need to save the 23467c478bd9Sstevel@tonic-gate * original ioctl message before sending the requests 23477c478bd9Sstevel@tonic-gate */ 23487c478bd9Sstevel@tonic-gate mutex_enter(&ill->ill_lock); 23497c478bd9Sstevel@tonic-gate /* ipsq_pending_mp_add won't fail since we pass in a NULL connp */ 23507c478bd9Sstevel@tonic-gate (void) ipsq_pending_mp_add(NULL, ipif, ill->ill_wq, mp, 0); 23517c478bd9Sstevel@tonic-gate /* 23527c478bd9Sstevel@tonic-gate * Set ill_phys_addr_pend to zero. It will be set to the addr_type of 23537c478bd9Sstevel@tonic-gate * the DL_PHYS_ADDR_REQ in ill_dlpi_send() and ill_dlpi_done(). It will 23547c478bd9Sstevel@tonic-gate * be used to track which DL_PHYS_ADDR_REQ is being ACK'd/NAK'd. 23557c478bd9Sstevel@tonic-gate */ 23567c478bd9Sstevel@tonic-gate ill->ill_phys_addr_pend = 0; 23577c478bd9Sstevel@tonic-gate mutex_exit(&ill->ill_lock); 23587c478bd9Sstevel@tonic-gate 23597c478bd9Sstevel@tonic-gate if (attach_mp != NULL) { 23607c478bd9Sstevel@tonic-gate ip1dbg(("ill_dl_phys: attach\n")); 23617c478bd9Sstevel@tonic-gate ill_dlpi_send(ill, attach_mp); 23627c478bd9Sstevel@tonic-gate } 23637c478bd9Sstevel@tonic-gate ill_dlpi_send(ill, bind_mp); 23647c478bd9Sstevel@tonic-gate ill_dlpi_send(ill, info_mp); 23651cb875aeSCathy Zhou 23661cb875aeSCathy Zhou /* 23671cb875aeSCathy Zhou * Send the capability request to get the VRRP capability information. 23681cb875aeSCathy Zhou */ 23691cb875aeSCathy Zhou ill_capability_send(ill, capab_mp); 23701cb875aeSCathy Zhou 23712b24ab6bSSebastien Roy if (v6token_mp != NULL) 23727c478bd9Sstevel@tonic-gate ill_dlpi_send(ill, v6token_mp); 23732b24ab6bSSebastien Roy if (v6lla_mp != NULL) 23747c478bd9Sstevel@tonic-gate ill_dlpi_send(ill, v6lla_mp); 23752b24ab6bSSebastien Roy if (dest_mp != NULL) 23762b24ab6bSSebastien Roy ill_dlpi_send(ill, dest_mp); 23777c478bd9Sstevel@tonic-gate ill_dlpi_send(ill, phys_mp); 23787c478bd9Sstevel@tonic-gate ill_dlpi_send(ill, notify_mp); 23797c478bd9Sstevel@tonic-gate ill_dlpi_send(ill, unbind_mp); 23807c478bd9Sstevel@tonic-gate 23817c478bd9Sstevel@tonic-gate /* 23827c478bd9Sstevel@tonic-gate * This operation will complete in ip_rput_dlpi_writer with either 23837c478bd9Sstevel@tonic-gate * a DL_PHYS_ADDR_ACK or DL_ERROR_ACK. 23847c478bd9Sstevel@tonic-gate */ 23857c478bd9Sstevel@tonic-gate return (EINPROGRESS); 23867c478bd9Sstevel@tonic-gate bad: 23877c478bd9Sstevel@tonic-gate freemsg(v6token_mp); 23887c478bd9Sstevel@tonic-gate freemsg(v6lla_mp); 23892b24ab6bSSebastien Roy freemsg(dest_mp); 23907c478bd9Sstevel@tonic-gate freemsg(phys_mp); 23917c478bd9Sstevel@tonic-gate freemsg(info_mp); 23927c478bd9Sstevel@tonic-gate freemsg(attach_mp); 23937c478bd9Sstevel@tonic-gate freemsg(bind_mp); 23941cb875aeSCathy Zhou freemsg(capab_mp); 23957c478bd9Sstevel@tonic-gate freemsg(unbind_mp); 23967c478bd9Sstevel@tonic-gate freemsg(notify_mp); 23977c478bd9Sstevel@tonic-gate return (ENOMEM); 23987c478bd9Sstevel@tonic-gate } 23997c478bd9Sstevel@tonic-gate 2400bd670b35SErik Nordmark /* Add room for tcp+ip headers */ 24017c478bd9Sstevel@tonic-gate uint_t ip_loopback_mtu_v6plus = IP_LOOPBACK_MTU + IPV6_HDR_LEN + 20; 24027c478bd9Sstevel@tonic-gate 24037c478bd9Sstevel@tonic-gate /* 24047c478bd9Sstevel@tonic-gate * DLPI is up. 24057c478bd9Sstevel@tonic-gate * Create all the IREs associated with an interface bring up multicast. 24067c478bd9Sstevel@tonic-gate * Set the interface flag and finish other initialization 24077c478bd9Sstevel@tonic-gate * that potentially had to be differed to after DL_BIND_ACK. 24087c478bd9Sstevel@tonic-gate */ 24097c478bd9Sstevel@tonic-gate int 24107c478bd9Sstevel@tonic-gate ipif_up_done_v6(ipif_t *ipif) 24117c478bd9Sstevel@tonic-gate { 24127c478bd9Sstevel@tonic-gate ill_t *ill = ipif->ipif_ill; 24137c478bd9Sstevel@tonic-gate int err; 24147c478bd9Sstevel@tonic-gate boolean_t loopback = B_FALSE; 24157c478bd9Sstevel@tonic-gate 24167c478bd9Sstevel@tonic-gate ip1dbg(("ipif_up_done_v6(%s:%u)\n", 24177c478bd9Sstevel@tonic-gate ipif->ipif_ill->ill_name, ipif->ipif_id)); 2418bd670b35SErik Nordmark DTRACE_PROBE3(ipif__downup, char *, "ipif_up_done_v6", 2419bd670b35SErik Nordmark ill_t *, ill, ipif_t *, ipif); 24207c478bd9Sstevel@tonic-gate 24217c478bd9Sstevel@tonic-gate /* Check if this is a loopback interface */ 24227c478bd9Sstevel@tonic-gate if (ipif->ipif_ill->ill_wq == NULL) 24237c478bd9Sstevel@tonic-gate loopback = B_TRUE; 24247c478bd9Sstevel@tonic-gate 24257c478bd9Sstevel@tonic-gate ASSERT(ipif->ipif_isv6); 24267c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&ipif->ipif_ill->ill_lock)); 24277c478bd9Sstevel@tonic-gate 2428bd670b35SErik Nordmark if (IS_LOOPBACK(ill) || ill->ill_net_type == IRE_IF_NORESOLVER) { 2429bd670b35SErik Nordmark nce_t *loop_nce = NULL; 2430bd670b35SErik Nordmark uint16_t flags = (NCE_F_MYADDR | NCE_F_NONUD | NCE_F_AUTHORITY); 24317c478bd9Sstevel@tonic-gate 24327c478bd9Sstevel@tonic-gate /* 24337c478bd9Sstevel@tonic-gate * lo0:1 and subsequent ipifs were marked IRE_LOCAL in 24347c478bd9Sstevel@tonic-gate * ipif_lookup_on_name(), but in the case of zones we can have 24357c478bd9Sstevel@tonic-gate * several loopback addresses on lo0. So all the interfaces with 24367c478bd9Sstevel@tonic-gate * loopback addresses need to be marked IRE_LOOPBACK. 24377c478bd9Sstevel@tonic-gate */ 24387c478bd9Sstevel@tonic-gate if (IN6_ARE_ADDR_EQUAL(&ipif->ipif_v6lcl_addr, &ipv6_loopback)) 24397c478bd9Sstevel@tonic-gate ipif->ipif_ire_type = IRE_LOOPBACK; 24407c478bd9Sstevel@tonic-gate else 24417c478bd9Sstevel@tonic-gate ipif->ipif_ire_type = IRE_LOCAL; 2442bd670b35SErik Nordmark if (ill->ill_net_type != IRE_LOOPBACK) 2443bd670b35SErik Nordmark flags |= NCE_F_PUBLISH; 2444bd670b35SErik Nordmark err = nce_lookup_then_add_v6(ill, NULL, 2445bd670b35SErik Nordmark ill->ill_phys_addr_length, 2446bd670b35SErik Nordmark &ipif->ipif_v6lcl_addr, flags, ND_REACHABLE, &loop_nce); 2447bd670b35SErik Nordmark 2448bd670b35SErik Nordmark /* A shared-IP zone sees EEXIST for lo0:N */ 2449bd670b35SErik Nordmark if (err == 0 || err == EEXIST) { 2450bd670b35SErik Nordmark ipif->ipif_added_nce = 1; 2451bd670b35SErik Nordmark loop_nce->nce_ipif_cnt++; 2452bd670b35SErik Nordmark nce_refrele(loop_nce); 2453bd670b35SErik Nordmark err = 0; 2454bd670b35SErik Nordmark } else { 2455bd670b35SErik Nordmark ASSERT(loop_nce == NULL); 2456bd670b35SErik Nordmark return (err); 2457bd670b35SErik Nordmark } 24587c478bd9Sstevel@tonic-gate } 24597c478bd9Sstevel@tonic-gate 2460bd670b35SErik Nordmark err = ipif_add_ires_v6(ipif, loopback); 2461bd670b35SErik Nordmark if (err != 0) { 24627c478bd9Sstevel@tonic-gate /* 2463bd670b35SErik Nordmark * See comments about return value from 2464bd670b35SErik Nordmark * ipif_addr_availability_check() in ipif_add_ires_v6(). 24657c478bd9Sstevel@tonic-gate */ 2466bd670b35SErik Nordmark if (err != EADDRINUSE) { 2467bd670b35SErik Nordmark ipif_ndp_down(ipif); 24687c478bd9Sstevel@tonic-gate } else { 2469bd670b35SErik Nordmark /* 2470bd670b35SErik Nordmark * Make IPMP aware of the deleted ipif so that 2471bd670b35SErik Nordmark * the needed ipmp cleanup (e.g., of ipif_bound_ill) 2472bd670b35SErik Nordmark * can be completed. Note that we do not want to 2473bd670b35SErik Nordmark * destroy the nce that was created on the ipmp_ill 2474bd670b35SErik Nordmark * for the active copy of the duplicate address in 2475bd670b35SErik Nordmark * use. 2476bd670b35SErik Nordmark */ 2477bd670b35SErik Nordmark if (IS_IPMP(ill)) 2478bd670b35SErik Nordmark ipmp_illgrp_del_ipif(ill->ill_grp, ipif); 2479bd670b35SErik Nordmark err = EADDRNOTAVAIL; 24807c478bd9Sstevel@tonic-gate } 2481bd670b35SErik Nordmark return (err); 2482bd670b35SErik Nordmark } 2483bd670b35SErik Nordmark 2484bd670b35SErik Nordmark if (ill->ill_ipif_up_count == 1 && !loopback) { 2485bd670b35SErik Nordmark /* Recover any additional IREs entries for this ill */ 2486bd670b35SErik Nordmark (void) ill_recover_saved_ire(ill); 2487bd670b35SErik Nordmark } 2488bd670b35SErik Nordmark 2489bd670b35SErik Nordmark if (ill->ill_need_recover_multicast) { 2490bd670b35SErik Nordmark /* 2491bd670b35SErik Nordmark * Need to recover all multicast memberships in the driver. 2492bd670b35SErik Nordmark * This had to be deferred until we had attached. 2493bd670b35SErik Nordmark */ 2494bd670b35SErik Nordmark ill_recover_multicast(ill); 2495bd670b35SErik Nordmark } 2496bd670b35SErik Nordmark 2497bd670b35SErik Nordmark if (ill->ill_ipif_up_count == 1) { 2498bd670b35SErik Nordmark /* 2499bd670b35SErik Nordmark * Since the interface is now up, it may now be active. 2500bd670b35SErik Nordmark */ 2501bd670b35SErik Nordmark if (IS_UNDER_IPMP(ill)) 2502bd670b35SErik Nordmark ipmp_ill_refresh_active(ill); 2503bd670b35SErik Nordmark } 2504bd670b35SErik Nordmark 2505bd670b35SErik Nordmark /* Join the allhosts multicast address and the solicited node MC */ 2506bd670b35SErik Nordmark ipif_multicast_up(ipif); 2507bd670b35SErik Nordmark 2508bd670b35SErik Nordmark /* Perhaps ilgs should use this ill */ 2509bd670b35SErik Nordmark update_conn_ill(NULL, ill->ill_ipst); 2510bd670b35SErik Nordmark 2511bd670b35SErik Nordmark if (ipif->ipif_addr_ready) 2512bd670b35SErik Nordmark ipif_up_notify(ipif); 2513bd670b35SErik Nordmark 2514bd670b35SErik Nordmark return (0); 2515bd670b35SErik Nordmark } 2516bd670b35SErik Nordmark 2517bd670b35SErik Nordmark /* 2518bd670b35SErik Nordmark * Add the IREs associated with the ipif. 2519bd670b35SErik Nordmark * Those MUST be explicitly removed in ipif_delete_ires_v6. 2520bd670b35SErik Nordmark */ 2521bd670b35SErik Nordmark static int 2522bd670b35SErik Nordmark ipif_add_ires_v6(ipif_t *ipif, boolean_t loopback) 2523bd670b35SErik Nordmark { 2524bd670b35SErik Nordmark ill_t *ill = ipif->ipif_ill; 2525bd670b35SErik Nordmark ip_stack_t *ipst = ill->ill_ipst; 2526bd670b35SErik Nordmark in6_addr_t v6addr; 2527bd670b35SErik Nordmark in6_addr_t route_mask; 2528bd670b35SErik Nordmark int err; 2529bd670b35SErik Nordmark char buf[INET6_ADDRSTRLEN]; 2530bd670b35SErik Nordmark ire_t *ire_local = NULL; /* LOCAL or LOOPBACK */ 25310e0e37a8SErik Nordmark ire_t *ire_if = NULL; 2532a1b6bb22SNitin Hande in6_addr_t *gw; 25337c478bd9Sstevel@tonic-gate 25347c478bd9Sstevel@tonic-gate if (!IN6_IS_ADDR_UNSPECIFIED(&ipif->ipif_v6lcl_addr) && 25357c478bd9Sstevel@tonic-gate !(ipif->ipif_flags & IPIF_NOLOCAL)) { 253645916cd2Sjpk 253745916cd2Sjpk /* 253845916cd2Sjpk * If we're on a labeled system then make sure that zone- 253945916cd2Sjpk * private addresses have proper remote host database entries. 254045916cd2Sjpk */ 254145916cd2Sjpk if (is_system_labeled() && 254245916cd2Sjpk ipif->ipif_ire_type != IRE_LOOPBACK) { 254345916cd2Sjpk if (ip6opt_ls == 0) { 254445916cd2Sjpk cmn_err(CE_WARN, "IPv6 not enabled " 254545916cd2Sjpk "via /etc/system"); 254645916cd2Sjpk return (EINVAL); 254745916cd2Sjpk } 254845916cd2Sjpk if (!tsol_check_interface_address(ipif)) 254945916cd2Sjpk return (EINVAL); 255045916cd2Sjpk } 255145916cd2Sjpk 2552a1b6bb22SNitin Hande if (loopback) 2553a1b6bb22SNitin Hande gw = &ipif->ipif_v6lcl_addr; 2554a1b6bb22SNitin Hande else 2555a1b6bb22SNitin Hande gw = NULL; 2556a1b6bb22SNitin Hande 25577c478bd9Sstevel@tonic-gate /* Register the source address for __sin6_src_id */ 25587c478bd9Sstevel@tonic-gate err = ip_srcid_insert(&ipif->ipif_v6lcl_addr, 2559f4b3ec61Sdh155122 ipif->ipif_zoneid, ipst); 25607c478bd9Sstevel@tonic-gate if (err != 0) { 2561bd670b35SErik Nordmark ip0dbg(("ipif_add_ires_v6: srcid_insert %d\n", err)); 25627c478bd9Sstevel@tonic-gate return (err); 25637c478bd9Sstevel@tonic-gate } 25647c478bd9Sstevel@tonic-gate /* 25657c478bd9Sstevel@tonic-gate * If the interface address is set, create the LOCAL 25667c478bd9Sstevel@tonic-gate * or LOOPBACK IRE. 25677c478bd9Sstevel@tonic-gate */ 2568bd670b35SErik Nordmark ip1dbg(("ipif_add_ires_v6: creating IRE %d for %s\n", 25697c478bd9Sstevel@tonic-gate ipif->ipif_ire_type, 25707c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, &ipif->ipif_v6lcl_addr, 25717c478bd9Sstevel@tonic-gate buf, sizeof (buf)))); 25727c478bd9Sstevel@tonic-gate 2573bd670b35SErik Nordmark ire_local = ire_create_v6( 25747c478bd9Sstevel@tonic-gate &ipif->ipif_v6lcl_addr, /* dest address */ 25757c478bd9Sstevel@tonic-gate &ipv6_all_ones, /* mask */ 2576a1b6bb22SNitin Hande gw, /* gateway */ 25777c478bd9Sstevel@tonic-gate ipif->ipif_ire_type, /* LOCAL or LOOPBACK */ 2578bd670b35SErik Nordmark ipif->ipif_ill, /* interface */ 2579bd670b35SErik Nordmark ipif->ipif_zoneid, 2580bd670b35SErik Nordmark ((ipif->ipif_flags & IPIF_PRIVATE) ? 2581bd670b35SErik Nordmark RTF_PRIVATE : 0) | RTF_KERNEL, 2582f4b3ec61Sdh155122 NULL, 2583f4b3ec61Sdh155122 ipst); 2584bd670b35SErik Nordmark if (ire_local == NULL) { 2585bd670b35SErik Nordmark ip1dbg(("ipif_up_done_v6: NULL ire_local\n")); 2586bd670b35SErik Nordmark err = ENOMEM; 2587bd670b35SErik Nordmark goto bad; 2588bd670b35SErik Nordmark } 25897c478bd9Sstevel@tonic-gate } 25907c478bd9Sstevel@tonic-gate 25912b24ab6bSSebastien Roy /* Set up the IRE_IF_RESOLVER or IRE_IF_NORESOLVER, as appropriate. */ 2592bd670b35SErik Nordmark if (!loopback && !(ipif->ipif_flags & IPIF_NOXMIT) && 25937c478bd9Sstevel@tonic-gate !(IN6_IS_ADDR_UNSPECIFIED(&ipif->ipif_v6subnet) && 25947c478bd9Sstevel@tonic-gate IN6_IS_ADDR_UNSPECIFIED(&ipif->ipif_v6net_mask))) { 25957c478bd9Sstevel@tonic-gate /* ipif_v6subnet is ipif_v6pp_dst_addr for pt-pt */ 25967c478bd9Sstevel@tonic-gate v6addr = ipif->ipif_v6subnet; 25977c478bd9Sstevel@tonic-gate 25987c478bd9Sstevel@tonic-gate if (ipif->ipif_flags & IPIF_POINTOPOINT) { 25997c478bd9Sstevel@tonic-gate route_mask = ipv6_all_ones; 26007c478bd9Sstevel@tonic-gate } else { 26017c478bd9Sstevel@tonic-gate route_mask = ipif->ipif_v6net_mask; 26027c478bd9Sstevel@tonic-gate } 26037c478bd9Sstevel@tonic-gate 2604bd670b35SErik Nordmark ip1dbg(("ipif_add_ires_v6: creating if IRE %d for %s\n", 26057c478bd9Sstevel@tonic-gate ill->ill_net_type, 26067c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, &v6addr, buf, sizeof (buf)))); 26077c478bd9Sstevel@tonic-gate 26080e0e37a8SErik Nordmark ire_if = ire_create_v6( 26097c478bd9Sstevel@tonic-gate &v6addr, /* dest pref */ 26107c478bd9Sstevel@tonic-gate &route_mask, /* mask */ 2611bd670b35SErik Nordmark &ipif->ipif_v6lcl_addr, /* gateway */ 26127c478bd9Sstevel@tonic-gate ill->ill_net_type, /* IF_[NO]RESOLVER */ 2613bd670b35SErik Nordmark ipif->ipif_ill, 2614bd670b35SErik Nordmark ipif->ipif_zoneid, 2615bd670b35SErik Nordmark ((ipif->ipif_flags & IPIF_PRIVATE) ? 2616bd670b35SErik Nordmark RTF_PRIVATE : 0) | RTF_KERNEL, 2617f4b3ec61Sdh155122 NULL, 2618f4b3ec61Sdh155122 ipst); 26190e0e37a8SErik Nordmark if (ire_if == NULL) { 26200e0e37a8SErik Nordmark ip1dbg(("ipif_up_done: NULL ire_if\n")); 26217c478bd9Sstevel@tonic-gate err = ENOMEM; 26227c478bd9Sstevel@tonic-gate goto bad; 26237c478bd9Sstevel@tonic-gate } 26247c478bd9Sstevel@tonic-gate } 26257c478bd9Sstevel@tonic-gate 26267c478bd9Sstevel@tonic-gate /* 2627e11c3f44Smeem * Need to atomically check for IP address availability under 2628e11c3f44Smeem * ip_addr_avail_lock. ill_g_lock is held as reader to ensure no new 2629e11c3f44Smeem * ills or new ipifs can be added while we are checking availability. 26307c478bd9Sstevel@tonic-gate */ 2631f4b3ec61Sdh155122 rw_enter(&ipst->ips_ill_g_lock, RW_READER); 2632f4b3ec61Sdh155122 mutex_enter(&ipst->ips_ip_addr_avail_lock); 26337c478bd9Sstevel@tonic-gate ill->ill_ipif_up_count++; 26347c478bd9Sstevel@tonic-gate ipif->ipif_flags |= IPIF_UP; 26357c478bd9Sstevel@tonic-gate err = ip_addr_availability_check(ipif); 2636f4b3ec61Sdh155122 mutex_exit(&ipst->ips_ip_addr_avail_lock); 2637f4b3ec61Sdh155122 rw_exit(&ipst->ips_ill_g_lock); 26387c478bd9Sstevel@tonic-gate 26397c478bd9Sstevel@tonic-gate if (err != 0) { 26407c478bd9Sstevel@tonic-gate /* 26417c478bd9Sstevel@tonic-gate * Our address may already be up on the same ill. In this case, 26427c478bd9Sstevel@tonic-gate * the external resolver entry for our ipif replaced the one for 26437c478bd9Sstevel@tonic-gate * the other ipif. So we don't want to delete it (otherwise the 26447c478bd9Sstevel@tonic-gate * other ipif would be unable to send packets). 26457c478bd9Sstevel@tonic-gate * ip_addr_availability_check() identifies this case for us and 2646bd670b35SErik Nordmark * returns EADDRINUSE; Caller must turn it into EADDRNOTAVAIL 26477c478bd9Sstevel@tonic-gate * which is the expected error code. 26489294ad19SSowmini Varadhan * 2649bd670b35SErik Nordmark * Note that ipif_ndp_down() will only delete the nce in the 2650bd670b35SErik Nordmark * case when the nce_ipif_cnt drops to 0. 26517c478bd9Sstevel@tonic-gate */ 26527c478bd9Sstevel@tonic-gate ill->ill_ipif_up_count--; 26537c478bd9Sstevel@tonic-gate ipif->ipif_flags &= ~IPIF_UP; 26547c478bd9Sstevel@tonic-gate goto bad; 26557c478bd9Sstevel@tonic-gate } 26567c478bd9Sstevel@tonic-gate 26577c478bd9Sstevel@tonic-gate /* 2658e11c3f44Smeem * Add in all newly created IREs. 26590e0e37a8SErik Nordmark * We add the IRE_INTERFACE before the IRE_LOCAL to ensure 26600e0e37a8SErik Nordmark * that lookups find the IRE_LOCAL even if the IRE_INTERFACE is 26610e0e37a8SErik Nordmark * a /128 route. 26627c478bd9Sstevel@tonic-gate */ 26630e0e37a8SErik Nordmark if (ire_if != NULL) { 26640e0e37a8SErik Nordmark ire_if = ire_add(ire_if); 26650e0e37a8SErik Nordmark if (ire_if == NULL) { 26660e0e37a8SErik Nordmark err = ENOMEM; 26670e0e37a8SErik Nordmark goto bad2; 26680e0e37a8SErik Nordmark } 26690e0e37a8SErik Nordmark #ifdef DEBUG 26700e0e37a8SErik Nordmark ire_refhold_notr(ire_if); 26710e0e37a8SErik Nordmark ire_refrele(ire_if); 26720e0e37a8SErik Nordmark #endif 26730e0e37a8SErik Nordmark } 2674bd670b35SErik Nordmark if (ire_local != NULL) { 2675bd670b35SErik Nordmark ire_local = ire_add(ire_local); 26760e0e37a8SErik Nordmark if (ire_local == NULL) { 26770e0e37a8SErik Nordmark err = ENOMEM; 26780e0e37a8SErik Nordmark goto bad2; 26790e0e37a8SErik Nordmark } 2680bd670b35SErik Nordmark #ifdef DEBUG 2681bd670b35SErik Nordmark ire_refhold_notr(ire_local); 2682bd670b35SErik Nordmark ire_refrele(ire_local); 2683bd670b35SErik Nordmark #endif 2684bd670b35SErik Nordmark } 2685bd670b35SErik Nordmark rw_enter(&ipst->ips_ill_g_lock, RW_WRITER); 2686bd670b35SErik Nordmark if (ire_local != NULL) 2687bd670b35SErik Nordmark ipif->ipif_ire_local = ire_local; 26880e0e37a8SErik Nordmark if (ire_if != NULL) 26890e0e37a8SErik Nordmark ipif->ipif_ire_if = ire_if; 2690bd670b35SErik Nordmark rw_exit(&ipst->ips_ill_g_lock); 2691bd670b35SErik Nordmark ire_local = NULL; 26920e0e37a8SErik Nordmark ire_if = NULL; 26937c478bd9Sstevel@tonic-gate 2694b127ac41SPhilip Kirk if (ipif->ipif_addr_ready) 2695b127ac41SPhilip Kirk ipif_up_notify(ipif); 26967c478bd9Sstevel@tonic-gate return (0); 26977c478bd9Sstevel@tonic-gate 26980e0e37a8SErik Nordmark bad2: 26990e0e37a8SErik Nordmark ill->ill_ipif_up_count--; 27000e0e37a8SErik Nordmark ipif->ipif_flags &= ~IPIF_UP; 27010e0e37a8SErik Nordmark 27027c478bd9Sstevel@tonic-gate bad: 2703bd670b35SErik Nordmark if (ire_local != NULL) 2704bd670b35SErik Nordmark ire_delete(ire_local); 27050e0e37a8SErik Nordmark if (ire_if != NULL) 27060e0e37a8SErik Nordmark ire_delete(ire_if); 27070e0e37a8SErik Nordmark 27080e0e37a8SErik Nordmark rw_enter(&ipst->ips_ill_g_lock, RW_WRITER); 27090e0e37a8SErik Nordmark ire_local = ipif->ipif_ire_local; 27100e0e37a8SErik Nordmark ipif->ipif_ire_local = NULL; 27110e0e37a8SErik Nordmark ire_if = ipif->ipif_ire_if; 27120e0e37a8SErik Nordmark ipif->ipif_ire_if = NULL; 27130e0e37a8SErik Nordmark rw_exit(&ipst->ips_ill_g_lock); 27140e0e37a8SErik Nordmark if (ire_local != NULL) { 27150e0e37a8SErik Nordmark ire_delete(ire_local); 27160e0e37a8SErik Nordmark ire_refrele_notr(ire_local); 27170e0e37a8SErik Nordmark } 27180e0e37a8SErik Nordmark if (ire_if != NULL) { 27190e0e37a8SErik Nordmark ire_delete(ire_if); 27200e0e37a8SErik Nordmark ire_refrele_notr(ire_if); 27217c478bd9Sstevel@tonic-gate } 2722f4b3ec61Sdh155122 (void) ip_srcid_remove(&ipif->ipif_v6lcl_addr, ipif->ipif_zoneid, ipst); 27237c478bd9Sstevel@tonic-gate 27247c478bd9Sstevel@tonic-gate return (err); 27257c478bd9Sstevel@tonic-gate } 27267c478bd9Sstevel@tonic-gate 2727bd670b35SErik Nordmark /* Remove all the IREs created by ipif_add_ires_v6 */ 2728bd670b35SErik Nordmark void 2729bd670b35SErik Nordmark ipif_delete_ires_v6(ipif_t *ipif) 2730bd670b35SErik Nordmark { 2731bd670b35SErik Nordmark ill_t *ill = ipif->ipif_ill; 2732bd670b35SErik Nordmark ip_stack_t *ipst = ill->ill_ipst; 2733bd670b35SErik Nordmark ire_t *ire; 2734bd670b35SErik Nordmark 2735bd670b35SErik Nordmark rw_enter(&ipst->ips_ill_g_lock, RW_WRITER); 27360e0e37a8SErik Nordmark ire = ipif->ipif_ire_local; 2737bd670b35SErik Nordmark ipif->ipif_ire_local = NULL; 2738bd670b35SErik Nordmark rw_exit(&ipst->ips_ill_g_lock); 27390e0e37a8SErik Nordmark if (ire != NULL) { 27407c478bd9Sstevel@tonic-gate /* 2741bd670b35SErik Nordmark * Move count to ipif so we don't loose the count due to 2742bd670b35SErik Nordmark * a down/up dance. 2743bd670b35SErik Nordmark */ 2744bd670b35SErik Nordmark atomic_add_32(&ipif->ipif_ib_pkt_count, ire->ire_ib_pkt_count); 2745bd670b35SErik Nordmark 2746bd670b35SErik Nordmark ire_delete(ire); 2747bd670b35SErik Nordmark ire_refrele_notr(ire); 27480e0e37a8SErik Nordmark } 27490e0e37a8SErik Nordmark rw_enter(&ipst->ips_ill_g_lock, RW_WRITER); 27500e0e37a8SErik Nordmark ire = ipif->ipif_ire_if; 27510e0e37a8SErik Nordmark ipif->ipif_ire_if = NULL; 2752bd670b35SErik Nordmark rw_exit(&ipst->ips_ill_g_lock); 27530e0e37a8SErik Nordmark if (ire != NULL) { 2754bd670b35SErik Nordmark ire_delete(ire); 27550e0e37a8SErik Nordmark ire_refrele_notr(ire); 2756bd670b35SErik Nordmark } 2757bd670b35SErik Nordmark } 2758bd670b35SErik Nordmark 2759bd670b35SErik Nordmark /* 2760bd670b35SErik Nordmark * Delete an ND entry if it exists. 27617c478bd9Sstevel@tonic-gate */ 27627c478bd9Sstevel@tonic-gate /* ARGSUSED */ 27637c478bd9Sstevel@tonic-gate int 27647c478bd9Sstevel@tonic-gate ip_siocdelndp_v6(ipif_t *ipif, sin_t *dummy_sin, queue_t *q, mblk_t *mp, 27657c478bd9Sstevel@tonic-gate ip_ioctl_cmd_t *ipip, void *dummy_ifreq) 27667c478bd9Sstevel@tonic-gate { 27677c478bd9Sstevel@tonic-gate sin6_t *sin6; 27687c478bd9Sstevel@tonic-gate struct lifreq *lifr; 27697c478bd9Sstevel@tonic-gate lif_nd_req_t *lnr; 2770e11c3f44Smeem ill_t *ill = ipif->ipif_ill; 2771bd670b35SErik Nordmark nce_t *nce; 27727c478bd9Sstevel@tonic-gate 2773e11c3f44Smeem lifr = (struct lifreq *)mp->b_cont->b_cont->b_rptr; 27747c478bd9Sstevel@tonic-gate lnr = &lifr->lifr_nd; 27757c478bd9Sstevel@tonic-gate /* Only allow for logical unit zero i.e. not on "le0:17" */ 27767c478bd9Sstevel@tonic-gate if (ipif->ipif_id != 0) 27777c478bd9Sstevel@tonic-gate return (EINVAL); 27787c478bd9Sstevel@tonic-gate 27797c478bd9Sstevel@tonic-gate if (!ipif->ipif_isv6) 27807c478bd9Sstevel@tonic-gate return (EINVAL); 27817c478bd9Sstevel@tonic-gate 27827c478bd9Sstevel@tonic-gate if (lnr->lnr_addr.ss_family != AF_INET6) 27837c478bd9Sstevel@tonic-gate return (EAFNOSUPPORT); 27847c478bd9Sstevel@tonic-gate 27857c478bd9Sstevel@tonic-gate sin6 = (sin6_t *)&lnr->lnr_addr; 2786e11c3f44Smeem 2787e11c3f44Smeem /* 2788e11c3f44Smeem * Since ND mappings must be consistent across an IPMP group, prohibit 2789bd670b35SErik Nordmark * deleting ND mappings on underlying interfaces. 2790bd670b35SErik Nordmark * Don't allow deletion of mappings for local addresses. 2791e11c3f44Smeem */ 2792e11c3f44Smeem if (IS_UNDER_IPMP(ill)) 2793e11c3f44Smeem return (EPERM); 2794e11c3f44Smeem 2795bd670b35SErik Nordmark nce = nce_lookup_v6(ill, &sin6->sin6_addr); 27967c478bd9Sstevel@tonic-gate if (nce == NULL) 27977c478bd9Sstevel@tonic-gate return (ESRCH); 2798bd670b35SErik Nordmark 2799bd670b35SErik Nordmark if (NCE_MYADDR(nce->nce_common)) { 2800bd670b35SErik Nordmark nce_refrele(nce); 2801bd670b35SErik Nordmark return (EPERM); 2802bd670b35SErik Nordmark } 2803bd670b35SErik Nordmark 2804bd670b35SErik Nordmark /* 2805bd670b35SErik Nordmark * delete the nce_common which will also delete the nces on any 2806bd670b35SErik Nordmark * under_ill in the case of ipmp. 2807bd670b35SErik Nordmark */ 2808bd670b35SErik Nordmark ncec_delete(nce->nce_common); 2809bd670b35SErik Nordmark nce_refrele(nce); 28107c478bd9Sstevel@tonic-gate return (0); 28117c478bd9Sstevel@tonic-gate } 28127c478bd9Sstevel@tonic-gate 28137c478bd9Sstevel@tonic-gate /* 28147c478bd9Sstevel@tonic-gate * Return nbr cache info. 28157c478bd9Sstevel@tonic-gate */ 28167c478bd9Sstevel@tonic-gate /* ARGSUSED */ 28177c478bd9Sstevel@tonic-gate int 28187c478bd9Sstevel@tonic-gate ip_siocqueryndp_v6(ipif_t *ipif, sin_t *dummy_sin, queue_t *q, mblk_t *mp, 28197c478bd9Sstevel@tonic-gate ip_ioctl_cmd_t *ipip, void *dummy_ifreq) 28207c478bd9Sstevel@tonic-gate { 28217c478bd9Sstevel@tonic-gate ill_t *ill = ipif->ipif_ill; 28227c478bd9Sstevel@tonic-gate struct lifreq *lifr; 28237c478bd9Sstevel@tonic-gate lif_nd_req_t *lnr; 28247c478bd9Sstevel@tonic-gate 28257c478bd9Sstevel@tonic-gate lifr = (struct lifreq *)mp->b_cont->b_cont->b_rptr; 28267c478bd9Sstevel@tonic-gate lnr = &lifr->lifr_nd; 28277c478bd9Sstevel@tonic-gate /* Only allow for logical unit zero i.e. not on "le0:17" */ 28287c478bd9Sstevel@tonic-gate if (ipif->ipif_id != 0) 28297c478bd9Sstevel@tonic-gate return (EINVAL); 28307c478bd9Sstevel@tonic-gate 28317c478bd9Sstevel@tonic-gate if (!ipif->ipif_isv6) 28327c478bd9Sstevel@tonic-gate return (EINVAL); 28337c478bd9Sstevel@tonic-gate 28347c478bd9Sstevel@tonic-gate if (lnr->lnr_addr.ss_family != AF_INET6) 28357c478bd9Sstevel@tonic-gate return (EAFNOSUPPORT); 28367c478bd9Sstevel@tonic-gate 28377c478bd9Sstevel@tonic-gate if (ill->ill_phys_addr_length > sizeof (lnr->lnr_hdw_addr)) 28387c478bd9Sstevel@tonic-gate return (EINVAL); 28397c478bd9Sstevel@tonic-gate 28407c478bd9Sstevel@tonic-gate return (ndp_query(ill, lnr)); 28417c478bd9Sstevel@tonic-gate } 28427c478bd9Sstevel@tonic-gate 28437c478bd9Sstevel@tonic-gate /* 28447c478bd9Sstevel@tonic-gate * Perform an update of the nd entry for the specified address. 28457c478bd9Sstevel@tonic-gate */ 28467c478bd9Sstevel@tonic-gate /* ARGSUSED */ 28477c478bd9Sstevel@tonic-gate int 28487c478bd9Sstevel@tonic-gate ip_siocsetndp_v6(ipif_t *ipif, sin_t *dummy_sin, queue_t *q, mblk_t *mp, 28497c478bd9Sstevel@tonic-gate ip_ioctl_cmd_t *ipip, void *dummy_ifreq) 28507c478bd9Sstevel@tonic-gate { 2851e11c3f44Smeem sin6_t *sin6; 28527c478bd9Sstevel@tonic-gate ill_t *ill = ipif->ipif_ill; 28537c478bd9Sstevel@tonic-gate struct lifreq *lifr; 28547c478bd9Sstevel@tonic-gate lif_nd_req_t *lnr; 2855e11c3f44Smeem ire_t *ire; 2856f4b3ec61Sdh155122 28577c478bd9Sstevel@tonic-gate lifr = (struct lifreq *)mp->b_cont->b_cont->b_rptr; 28587c478bd9Sstevel@tonic-gate lnr = &lifr->lifr_nd; 28597c478bd9Sstevel@tonic-gate /* Only allow for logical unit zero i.e. not on "le0:17" */ 28607c478bd9Sstevel@tonic-gate if (ipif->ipif_id != 0) 28617c478bd9Sstevel@tonic-gate return (EINVAL); 28627c478bd9Sstevel@tonic-gate 28637c478bd9Sstevel@tonic-gate if (!ipif->ipif_isv6) 28647c478bd9Sstevel@tonic-gate return (EINVAL); 28657c478bd9Sstevel@tonic-gate 28667c478bd9Sstevel@tonic-gate if (lnr->lnr_addr.ss_family != AF_INET6) 28677c478bd9Sstevel@tonic-gate return (EAFNOSUPPORT); 28687c478bd9Sstevel@tonic-gate 2869e11c3f44Smeem sin6 = (sin6_t *)&lnr->lnr_addr; 2870e11c3f44Smeem 2871e11c3f44Smeem /* 2872e11c3f44Smeem * Since ND mappings must be consistent across an IPMP group, prohibit 2873e11c3f44Smeem * updating ND mappings on underlying interfaces. Also, since ND 2874e11c3f44Smeem * mappings for IPMP data addresses are owned by IP itself, prohibit 2875e11c3f44Smeem * updating them. 2876e11c3f44Smeem */ 2877e11c3f44Smeem if (IS_UNDER_IPMP(ill)) 2878e11c3f44Smeem return (EPERM); 2879e11c3f44Smeem 2880e11c3f44Smeem if (IS_IPMP(ill)) { 2881bd670b35SErik Nordmark ire = ire_ftable_lookup_v6(&sin6->sin6_addr, NULL, NULL, 2882bd670b35SErik Nordmark IRE_LOCAL, ill, ALL_ZONES, NULL, 2883bd670b35SErik Nordmark MATCH_IRE_TYPE | MATCH_IRE_ILL, 0, ill->ill_ipst, NULL); 2884e11c3f44Smeem if (ire != NULL) { 2885e11c3f44Smeem ire_refrele(ire); 2886e11c3f44Smeem return (EPERM); 2887e11c3f44Smeem } 2888e11c3f44Smeem } 2889e11c3f44Smeem 28907c478bd9Sstevel@tonic-gate return (ndp_sioc_update(ill, lnr)); 28917c478bd9Sstevel@tonic-gate } 2892