ip_ndp.h revision 3448:aaf16568054b
1295009Sjkim/* 2162911Ssimon * CDDL HEADER START 3280297Sjkim * 4162911Ssimon * The contents of this file are subject to the terms of the 5162911Ssimon * Common Development and Distribution License (the "License"). 6162911Ssimon * You may not use this file except in compliance with the License. 7162911Ssimon * 8162911Ssimon * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9162911Ssimon * or http://www.opensolaris.org/os/licensing. 10162911Ssimon * See the License for the specific language governing permissions 11162911Ssimon * and limitations under the License. 12162911Ssimon * 13162911Ssimon * When distributing Covered Code, include this CDDL HEADER in each 14162911Ssimon * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15162911Ssimon * If applicable, add the following below this CDDL HEADER, with the 16162911Ssimon * fields enclosed by brackets "[]" replaced with your own identifying 17162911Ssimon * information: Portions Copyright [yyyy] [name of copyright owner] 18162911Ssimon * 19162911Ssimon * CDDL HEADER END 20162911Ssimon */ 21162911Ssimon/* 22162911Ssimon * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23162911Ssimon * Use is subject to license terms. 24162911Ssimon */ 25162911Ssimon 26162911Ssimon#ifndef _INET_IP_NDP_H 27280297Sjkim#define _INET_IP_NDP_H 28162911Ssimon 29162911Ssimon#pragma ident "%Z%%M% %I% %E% SMI" 30162911Ssimon 31162911Ssimon#include <sys/mutex.h> 32162911Ssimon#include <sys/stream.h> 33162911Ssimon#include <netinet/in.h> 34162911Ssimon#include <netinet/icmp6.h> 35162911Ssimon#include <inet/ip.h> 36162911Ssimon 37162911Ssimon/* 38162911Ssimon * Internal definitions for the kernel implementation of the IPv6 39162911Ssimon * Neighbor Discovery Protocol (NDP). 40162911Ssimon */ 41162911Ssimon 42162911Ssimon#ifdef __cplusplus 43162911Ssimonextern "C" { 44162911Ssimon#endif 45162911Ssimon 46162911Ssimon#ifdef _KERNEL 47162911Ssimon#define NCE_TABLE_SIZE 256 48162911Ssimon/* NDP Cache Entry */ 49162911Ssimontypedef struct nce_s { 50162911Ssimon struct nce_s *nce_next; /* Hash chain next pointer */ 51162911Ssimon struct nce_s **nce_ptpn; /* Pointer to previous next */ 52162911Ssimon struct ill_s *nce_ill; /* Associated ill */ 53162911Ssimon uint16_t nce_flags; /* See below */ 54162911Ssimon uint16_t nce_state; /* See reachability states in if.h */ 55162911Ssimon int16_t nce_pcnt; /* Probe counter */ 56162911Ssimon uint16_t nce_rcnt; /* Retransmit counter */ 57162911Ssimon in6_addr_t nce_addr; /* address of the nighbor */ 58162911Ssimon in6_addr_t nce_mask; /* If not all ones, mask allows an */ 59162911Ssimon /* entry to respond to requests for a group of addresses, for */ 60162911Ssimon /* instantance multicast addresses */ 61162911Ssimon in6_addr_t nce_extract_mask; /* For mappings */ 62162911Ssimon uint32_t nce_ll_extract_start; /* For mappings */ 63162911Ssimon#define nce_first_mp_to_free nce_fp_mp 64162911Ssimon mblk_t *nce_fp_mp; /* link layer fast path mp */ 65162911Ssimon mblk_t *nce_res_mp; /* DL_UNITDATA_REQ or link layer mp */ 66162911Ssimon mblk_t *nce_qd_mp; /* Head outgoing queued packets */ 67162911Ssimon#define nce_last_mp_to_free nce_qd_mp 68162911Ssimon mblk_t *nce_timer_mp; /* NDP timer mblk */ 69280297Sjkim mblk_t *nce_mp; /* mblk we are in, last to be freed */ 70162911Ssimon uint64_t nce_last; /* Time last reachable in msec */ 71280297Sjkim uint32_t nce_refcnt; /* nce active usage count */ 72167612Ssimon kmutex_t nce_lock; /* See comments on top for what */ 73162911Ssimon /* this field protects */ 74238405Sjkim int nce_unsolicit_count; /* Unsolicited Adv count */ 75280297Sjkim struct nce_s *nce_fastpath; /* for fastpath list */ 76280297Sjkim timeout_id_t nce_timeout_id; 77280297Sjkim uchar_t nce_ipversion; /* IPv4(ARP)/IPv6(NDP) version */ 78280297Sjkim uint_t nce_defense_count; /* number of NDP conflicts */ 79280297Sjkim uint_t nce_defense_time; /* last time defended (secs) */ 80280297Sjkim#ifdef NCE_DEBUG 81280297Sjkim th_trace_t *nce_trace[IP_TR_HASH_MAX]; 82280297Sjkim boolean_t nce_trace_disable; /* True when alloc fails */ 83280297Sjkim#endif 84280297Sjkim} nce_t; 85280297Sjkim 86238405Sjkim/* 87280297Sjkim * The ndp_g_t structure contains protocol specific information needed 88280297Sjkim * to synchronize and manage neighbor cache entries for IPv4 and IPv6. 89 * There are 2 such structures, ips_ndp4 and ips_ndp6. 90 * ips_ndp6 contains the data structures needed for IPv6 Neighbor Discovery. 91 * ips_ndp4 has IPv4 link layer info in its nce_t structures 92 * Note that the nce_t is not currently used as the arp cache itself; 93 * it is used for the following purposes: 94 * - queue packets in nce_qd_mp while waiting for arp resolution to complete 95 * - nce_{res, fp}_mp are used to track DL_UNITDATA request/responses. 96 * - track state of ARP resolution in the nce_state; 97 * 98 * Locking notes: 99 * ndp_g_lock protects neighbor cache tables access and 100 * insertion/removal of cache entries into/from these tables. 101 * nce_lock protects nce_pcnt, nce_rcnt, nce_qd_mp nce_state, 102 * nce_res_mp, nce_refcnt and nce_last. 103 * nce_refcnt is incremented for every ire pointing to this nce and 104 * every time ndp_lookup() finds an nce. 105 * Should there be a need to obtain nce_lock and ndp_g_lock, ndp_g_lock is 106 * acquired first. 107 * To avoid becoming exclusive when deleting NCEs, ndp_walk() routine holds 108 * the ndp_g_lock (i.e global lock) and marks NCEs to be deleted with 109 * NCE_F_CONDEMNED. When all active users of such NCEs are gone the walk 110 * routine passes a list for deletion to nce_ire_delete_list(). 111 */ 112typedef struct ndp_g_s { 113 kmutex_t ndp_g_lock; /* Lock protecting cache hash table */ 114 nce_t *nce_mask_entries; /* mask not all ones */ 115 nce_t *nce_hash_tbl[NCE_TABLE_SIZE]; 116 int ndp_g_walker; /* # of active thread walking hash list */ 117 boolean_t ndp_g_walker_cleanup; /* true implies defer deletion. */ 118} ndp_g_t; 119 120/* nce_flags */ 121#define NCE_F_PERMANENT 0x1 122#define NCE_F_MAPPING 0x2 123#define NCE_F_ISROUTER 0x4 124#define NCE_F_PROXY 0x8 125#define NCE_F_NONUD 0x10 126#define NCE_F_ANYCAST 0x20 127#define NCE_F_CONDEMNED 0x40 128#define NCE_F_UNSOL_ADV 0x80 129#define NCE_F_BCAST 0x100 130 131#define NCE_EXTERNAL_FLAGS_MASK \ 132 (NCE_F_PERMANENT | NCE_F_MAPPING | NCE_F_ISROUTER | NCE_F_NONUD | \ 133 NCE_F_ANYCAST | NCE_F_UNSOL_ADV) 134 135/* State REACHABLE, STALE, DELAY or PROBE */ 136#define NCE_ISREACHABLE(nce) \ 137 (((((nce)->nce_state) >= ND_REACHABLE) && \ 138 ((nce)->nce_state) <= ND_PROBE)) 139 140/* NDP flags set in SOL/ADV requests */ 141#define NDP_UNICAST 0x1 142#define NDP_ISROUTER 0x2 143#define NDP_SOLICITED 0x4 144#define NDP_ORIDE 0x8 145#define NDP_PROBE 0x10 146 147/* Number of packets queued in NDP for a neighbor */ 148#define ND_MAX_Q 4 149 150 151#ifdef NCE_DEBUG 152#define NCE_TRACE_REF(nce) nce_trace_ref(nce) 153#define NCE_UNTRACE_REF(nce) nce_untrace_ref(nce) 154#else 155#define NCE_TRACE_REF(nce) 156#define NCE_UNTRACE_REF(nce) 157#endif 158 159#define NCE_REFHOLD(nce) { \ 160 mutex_enter(&(nce)->nce_lock); \ 161 (nce)->nce_refcnt++; \ 162 ASSERT((nce)->nce_refcnt != 0); \ 163 NCE_TRACE_REF(nce); \ 164 mutex_exit(&(nce)->nce_lock); \ 165} 166 167#define NCE_REFHOLD_NOTR(nce) { \ 168 mutex_enter(&(nce)->nce_lock); \ 169 (nce)->nce_refcnt++; \ 170 ASSERT((nce)->nce_refcnt != 0); \ 171 mutex_exit(&(nce)->nce_lock); \ 172} 173 174#define NCE_REFHOLD_LOCKED(nce) { \ 175 ASSERT(MUTEX_HELD(&(nce)->nce_lock)); \ 176 (nce)->nce_refcnt++; \ 177 NCE_TRACE_REF(nce); \ 178} 179 180/* nce_inactive destroys the mutex thus no mutex_exit is needed */ 181#define NCE_REFRELE(nce) { \ 182 mutex_enter(&(nce)->nce_lock); \ 183 NCE_UNTRACE_REF(nce); \ 184 ASSERT((nce)->nce_refcnt != 0); \ 185 if (--(nce)->nce_refcnt == 0) \ 186 ndp_inactive(nce); \ 187 else { \ 188 mutex_exit(&(nce)->nce_lock);\ 189 } \ 190} 191 192#define NCE_REFRELE_NOTR(nce) { \ 193 mutex_enter(&(nce)->nce_lock); \ 194 ASSERT((nce)->nce_refcnt != 0); \ 195 if (--(nce)->nce_refcnt == 0) \ 196 ndp_inactive(nce); \ 197 else { \ 198 mutex_exit(&(nce)->nce_lock);\ 199 } \ 200} 201 202#define NDP_RESTART_TIMER(nce, ms) { \ 203 ASSERT(!MUTEX_HELD(&(nce)->nce_lock)); \ 204 if ((nce)->nce_timeout_id != 0) { \ 205 /* Ok to untimeout bad id. we don't hold a lock. */ \ 206 (void) untimeout((nce)->nce_timeout_id); \ 207 } \ 208 mutex_enter(&(nce)->nce_lock); \ 209 /* Don't start the timer if the nce has been deleted */ \ 210 if (!((nce)->nce_flags & NCE_F_CONDEMNED)) \ 211 nce->nce_timeout_id = timeout(ndp_timer, nce, \ 212 MSEC_TO_TICK(ms) == 0 ? 1 : MSEC_TO_TICK(ms)); \ 213 mutex_exit(&(nce)->nce_lock); \ 214} 215 216/* Structure for ndp_cache_count() */ 217typedef struct { 218 int ncc_total; /* Total number of NCEs */ 219 int ncc_host; /* NCE entries without R bit set */ 220} ncc_cache_count_t; 221 222/* 223 * Structure of ndp_cache_reclaim(). Each field is a fraction i.e. 1 means 224 * reclaim all, N means reclaim 1/Nth of all entries, 0 means reclaim none. 225 */ 226typedef struct { 227 int ncr_host; /* Fraction for host entries */ 228} nce_cache_reclaim_t; 229 230/* 231 * Structure for nce_delete_hw_changed; specifies an IPv4 address to link-layer 232 * address mapping. Any route that has a cached copy of a mapping for that 233 * IPv4 address that doesn't match the given mapping must be purged. 234 */ 235typedef struct { 236 ipaddr_t hwm_addr; /* IPv4 address */ 237 uint_t hwm_hwlen; /* Length of hardware address (may be 0) */ 238 uchar_t *hwm_hwaddr; /* Pointer to new hardware address, if any */ 239} nce_hw_map_t; 240 241/* When SAP is greater than zero address appears before SAP */ 242#define NCE_LL_ADDR_OFFSET(ill) (((ill)->ill_sap_length) < 0 ? \ 243 (sizeof (dl_unitdata_req_t)) : \ 244 ((sizeof (dl_unitdata_req_t)) + (ABS((ill)->ill_sap_length)))) 245 246#define NCE_LL_SAP_OFFSET(ill) (((ill)->ill_sap_length) < 0 ? \ 247 ((sizeof (dl_unitdata_req_t)) + ((ill)->ill_phys_addr_length)) : \ 248 (sizeof (dl_unitdata_req_t))) 249 250#ifdef _BIG_ENDIAN 251#define NCE_LL_SAP_COPY(ill, mp) \ 252 { \ 253 size_t abs_sap_len = ABS((ill)->ill_sap_length); \ 254 if (abs_sap_len > 0) { \ 255 ASSERT(abs_sap_len <= sizeof (uint32_t)); \ 256 ASSERT((mp)->b_rptr + NCE_LL_SAP_OFFSET(ill) + \ 257 abs_sap_len <= ((mp)->b_wptr)); \ 258 bcopy((uint8_t *)&(ill)->ill_sap + sizeof (ill->ill_sap) - \ 259 abs_sap_len, \ 260 ((mp)->b_rptr + NCE_LL_SAP_OFFSET(ill)), \ 261 abs_sap_len); \ 262 } \ 263 } 264#else 265#define NCE_LL_SAP_COPY(ill, mp) \ 266 { \ 267 size_t abs_sap_len = ABS((ill)->ill_sap_length); \ 268 if (abs_sap_len > 0) { \ 269 uint32_t abs_sap_len = ABS((ill)->ill_sap_length); \ 270 ASSERT(abs_sap_len <= sizeof (uint32_t)); \ 271 ASSERT((mp)->b_rptr + NCE_LL_SAP_OFFSET(ill) + \ 272 abs_sap_len <= ((mp)->b_wptr)); \ 273 bcopy(&((ill)->ill_sap), \ 274 ((mp)->b_rptr + NCE_LL_SAP_OFFSET(ill)), \ 275 abs_sap_len); \ 276 } \ 277 } 278#endif 279 280/* 281 * Exclusive-or the 6 bytes that are likely to contain the MAC 282 * address. Assumes table_size does not exceed 256. 283 * Assumes EUI-64 format for good hashing. 284 */ 285#define NCE_ADDR_HASH_V6(addr, table_size) \ 286 (((addr).s6_addr8[8] ^ (addr).s6_addr8[9] ^ \ 287 (addr).s6_addr8[10] ^ (addr).s6_addr8[13] ^ \ 288 (addr).s6_addr8[14] ^ (addr).s6_addr8[15]) % (table_size)) 289 290/* NDP Cache Entry Hash Table */ 291#define NCE_TABLE_SIZE 256 292 293extern void ndp_cache_count(nce_t *, char *); 294extern void ndp_cache_reclaim(nce_t *, char *); 295extern void ndp_delete(nce_t *); 296extern void ndp_delete_per_ill(nce_t *, uchar_t *); 297extern void ndp_fastpath_flush(nce_t *, char *); 298extern boolean_t ndp_fastpath_update(nce_t *, void *); 299extern nd_opt_hdr_t *ndp_get_option(nd_opt_hdr_t *, int, int); 300extern void ndp_inactive(nce_t *); 301extern void ndp_input(ill_t *, mblk_t *, mblk_t *); 302extern boolean_t ndp_lookup_ipaddr(in_addr_t, netstack_t *); 303extern nce_t *ndp_lookup_v6(ill_t *, const in6_addr_t *, boolean_t); 304extern nce_t *ndp_lookup_v4(ill_t *, const in_addr_t *, boolean_t); 305extern int ndp_lookup_then_add(ill_t *, uchar_t *, const void *, 306 const void *, const void *, uint32_t, uint16_t, 307 uint16_t, nce_t **, mblk_t *, mblk_t *); 308extern int ndp_mcastreq(ill_t *, const in6_addr_t *, uint32_t, uint32_t, 309 mblk_t *); 310extern int ndp_noresolver(ill_t *, const in6_addr_t *); 311extern void ndp_process(nce_t *, uchar_t *, uint32_t, boolean_t); 312extern int ndp_query(ill_t *, lif_nd_req_t *); 313extern int ndp_report(queue_t *, mblk_t *, caddr_t, cred_t *); 314extern int ndp_resolver(ill_t *, const in6_addr_t *, mblk_t *, zoneid_t); 315extern int ndp_sioc_update(ill_t *, lif_nd_req_t *); 316extern boolean_t ndp_verify_optlen(nd_opt_hdr_t *, int); 317extern void ndp_timer(void *); 318extern void ndp_walk(ill_t *, pfi_t, void *, ip_stack_t *); 319extern void ndp_walk_common(ndp_g_t *, ill_t *, pfi_t, 320 void *, boolean_t); 321extern int ndp_add(ill_t *, uchar_t *, const void *, 322 const void *, const void *, 323 uint32_t, uint16_t, uint16_t, nce_t **, mblk_t *, mblk_t *); 324extern boolean_t ndp_restart_dad(nce_t *); 325extern void ndp_do_recovery(ipif_t *); 326extern void nce_resolv_failed(nce_t *); 327extern void arp_resolv_failed(nce_t *); 328extern void nce_fastpath_list_add(nce_t *); 329extern void nce_fastpath_list_delete(nce_t *); 330extern void nce_fastpath_list_dispatch(ill_t *, 331 boolean_t (*)(nce_t *, void *), void *); 332extern void nce_queue_mp_common(nce_t *, mblk_t *, boolean_t); 333extern void ndp_flush_qd_mp(nce_t *); 334extern nce_t *nce_reinit(nce_t *); 335extern void nce_delete_hw_changed(nce_t *, void *); 336extern void nce_fastpath(nce_t *); 337 338#ifdef NCE_DEBUG 339extern void nce_trace_inactive(nce_t *); 340extern void nce_trace_ref(nce_t *); 341extern void nce_untrace_ref(nce_t *); 342extern int nce_thread_exit(nce_t *, caddr_t); 343#endif 344 345#endif /* _KERNEL */ 346 347#ifdef __cplusplus 348} 349#endif 350 351#endif /* _INET_IP_NDP_H */ 352