1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #ifndef _INET_IP_NDP_H 27 #define _INET_IP_NDP_H 28 29 #pragma ident "%Z%%M% %I% %E% SMI" 30 31 /* 32 * Internal definitions for the kernel implementation of the IPv6 33 * Neighbor Discovery Protocol (NDP). 34 */ 35 36 #ifdef __cplusplus 37 extern "C" { 38 #endif 39 40 #ifdef _KERNEL 41 #define NCE_TABLE_SIZE 256 42 /* NDP Cache Entry */ 43 typedef struct nce_s { 44 struct nce_s *nce_next; /* Hash chain next pointer */ 45 struct nce_s **nce_ptpn; /* Pointer to previous next */ 46 struct ill_s *nce_ill; /* Associated ill */ 47 uint16_t nce_flags; /* See below */ 48 uint16_t nce_state; /* See reachability states in if.h */ 49 int16_t nce_pcnt; /* Probe counter */ 50 uint16_t nce_rcnt; /* Retransmit counter */ 51 in6_addr_t nce_addr; /* address of the nighbor */ 52 in6_addr_t nce_mask; /* If not all ones, mask allows an */ 53 /* entry to respond to requests for a group of addresses, for */ 54 /* instantance multicast addresses */ 55 in6_addr_t nce_extract_mask; /* For mappings */ 56 uint32_t nce_ll_extract_start; /* For mappings */ 57 #define nce_first_mp_to_free nce_fp_mp 58 mblk_t *nce_fp_mp; /* link layer fast path mp */ 59 mblk_t *nce_res_mp; /* DL_UNITDATA_REQ or link layer mp */ 60 mblk_t *nce_qd_mp; /* Head outgoing queued packets */ 61 #define nce_last_mp_to_free nce_qd_mp 62 mblk_t *nce_timer_mp; /* NDP timer mblk */ 63 mblk_t *nce_mp; /* mblk we are in, last to be freed */ 64 uint64_t nce_last; /* Time last reachable in msec */ 65 uint32_t nce_refcnt; /* nce active usage count */ 66 kmutex_t nce_lock; /* See comments on top for what */ 67 /* this field protects */ 68 int nce_unsolicit_count; /* Unsolicited Adv count */ 69 struct nce_s *nce_fastpath; /* for fastpath list */ 70 timeout_id_t nce_timeout_id; 71 uchar_t nce_ipversion; /* IPv4(ARP)/IPv6(NDP) version */ 72 #ifdef NCE_DEBUG 73 th_trace_t *nce_trace[IP_TR_HASH_MAX]; 74 boolean_t nce_trace_disable; /* True when alloc fails */ 75 #endif 76 } nce_t; 77 78 /* 79 * The ndp_g_t structure contains protocol specific information needed 80 * to synchronize and manage neighbor cache entries for IPv4 and IPv6. 81 * There are 2 such structures, ndp4 and ndp6. 82 * ndp6 contains the data structures needed for IPv6 Neighbor Discovery. 83 * ndp4 has IPv4 link layer info in its nce_t structures 84 * Note that the nce_t is not currently used as the arp cache itself; 85 * it is used for the following purposes: 86 * - queue packets in nce_qd_mp while waiting for arp resolution to complete 87 * - nce_{res, fp}_mp are used to track DL_UNITDATA request/responses. 88 * - track state of ARP resolution in the nce_state; 89 * 90 * Locking notes: 91 * ndp_g_lock protects neighbor cache tables access and 92 * insertion/removal of cache entries into/from these tables. 93 * nce_lock protects nce_pcnt, nce_rcnt, nce_qd_mp nce_state, 94 * nce_res_mp, nce_refcnt and nce_last. 95 * nce_refcnt is incremented for every ire pointing to this nce and 96 * every time ndp_lookup() finds an nce. 97 * Should there be a need to obtain nce_lock and ndp_g_lock, ndp_g_lock is 98 * acquired first. 99 * To avoid becoming exclusive when deleting NCEs, ndp_walk() routine holds 100 * the ndp_g_lock (i.e global lock) and marks NCEs to be deleted with 101 * NCE_F_CONDEMNED. When all active users of such NCEs are gone the walk 102 * routine passes a list for deletion to nce_ire_delete_list(). 103 */ 104 typedef struct ndp_g_s { 105 kmutex_t ndp_g_lock; /* Lock protecting cache hash table */ 106 nce_t *nce_mask_entries; /* mask not all ones */ 107 nce_t *nce_hash_tbl[NCE_TABLE_SIZE]; 108 int ndp_g_walker; /* # of active thread walking hash list */ 109 boolean_t ndp_g_walker_cleanup; /* true implies defer deletion. */ 110 } ndp_g_t; 111 112 extern ndp_g_t ndp4, ndp6; 113 114 /* nce_flags */ 115 #define NCE_F_PERMANENT 0x1 116 #define NCE_F_MAPPING 0x2 117 #define NCE_F_ISROUTER 0x4 118 #define NCE_F_PROXY 0x8 119 #define NCE_F_NONUD 0x10 120 #define NCE_F_ANYCAST 0x20 121 #define NCE_F_CONDEMNED 0x40 122 #define NCE_F_UNSOL_ADV 0x80 123 124 #define NCE_EXTERNAL_FLAGS_MASK \ 125 (NCE_F_PERMANENT | NCE_F_MAPPING | NCE_F_ISROUTER | NCE_F_NONUD | \ 126 NCE_F_ANYCAST | NCE_F_UNSOL_ADV) 127 128 /* State REACHABLE, STALE, DELAY or PROBE */ 129 #define NCE_ISREACHABLE(nce) \ 130 (((((nce)->nce_state) >= ND_REACHABLE) && \ 131 ((nce)->nce_state) <= ND_PROBE)) 132 133 /* NDP flags set in SOL/ADV requests */ 134 #define NDP_UNICAST 0x1 135 #define NDP_ISROUTER 0x2 136 #define NDP_SOLICITED 0x4 137 #define NDP_ORIDE 0x8 138 139 /* Number of packets queued in NDP for a neighbor */ 140 #define ND_MAX_Q 4 141 142 143 #ifdef NCE_DEBUG 144 #define NCE_TRACE_REF(nce) nce_trace_ref(nce) 145 #define NCE_UNTRACE_REF(nce) nce_untrace_ref(nce) 146 #else 147 #define NCE_TRACE_REF(nce) 148 #define NCE_UNTRACE_REF(nce) 149 #endif 150 151 #define NCE_REFHOLD(nce) { \ 152 mutex_enter(&(nce)->nce_lock); \ 153 (nce)->nce_refcnt++; \ 154 ASSERT((nce)->nce_refcnt != 0); \ 155 NCE_TRACE_REF(nce); \ 156 mutex_exit(&(nce)->nce_lock); \ 157 } 158 159 #define NCE_REFHOLD_NOTR(nce) { \ 160 mutex_enter(&(nce)->nce_lock); \ 161 (nce)->nce_refcnt++; \ 162 ASSERT((nce)->nce_refcnt != 0); \ 163 mutex_exit(&(nce)->nce_lock); \ 164 } 165 166 #define NCE_REFHOLD_LOCKED(nce) { \ 167 ASSERT(MUTEX_HELD(&(nce)->nce_lock)); \ 168 (nce)->nce_refcnt++; \ 169 NCE_TRACE_REF(nce); \ 170 } 171 172 /* nce_inactive destroys the mutex thus no mutex_exit is needed */ 173 #define NCE_REFRELE(nce) { \ 174 mutex_enter(&(nce)->nce_lock); \ 175 NCE_UNTRACE_REF(nce); \ 176 ASSERT((nce)->nce_refcnt != 0); \ 177 if (--(nce)->nce_refcnt == 0) \ 178 ndp_inactive(nce); \ 179 else { \ 180 mutex_exit(&(nce)->nce_lock);\ 181 } \ 182 } 183 184 #define NCE_REFRELE_NOTR(nce) { \ 185 mutex_enter(&(nce)->nce_lock); \ 186 ASSERT((nce)->nce_refcnt != 0); \ 187 if (--(nce)->nce_refcnt == 0) \ 188 ndp_inactive(nce); \ 189 else { \ 190 mutex_exit(&(nce)->nce_lock);\ 191 } \ 192 } 193 194 #define NDP_RESTART_TIMER(nce, ms) { \ 195 ASSERT(!MUTEX_HELD(&(nce)->nce_lock)); \ 196 if ((nce)->nce_timeout_id != 0) { \ 197 /* Ok to untimeout bad id. we don't hold a lock. */ \ 198 (void) untimeout((nce)->nce_timeout_id); \ 199 } \ 200 mutex_enter(&(nce)->nce_lock); \ 201 /* Don't start the timer if the nce has been deleted */ \ 202 if (!((nce)->nce_flags & NCE_F_CONDEMNED)) \ 203 nce->nce_timeout_id = timeout(ndp_timer, nce, \ 204 MSEC_TO_TICK(ms) == 0 ? 1 : MSEC_TO_TICK(ms)); \ 205 mutex_exit(&(nce)->nce_lock); \ 206 } 207 208 /* Structure for ndp_cache_count() */ 209 typedef struct { 210 int ncc_total; /* Total number of NCEs */ 211 int ncc_host; /* NCE entries without R bit set */ 212 } ncc_cache_count_t; 213 214 /* 215 * Structure of ndp_cache_reclaim(). Each field is a fraction i.e. 1 means 216 * reclaim all, N means reclaim 1/Nth of all entries, 0 means reclaim none. 217 */ 218 typedef struct { 219 int ncr_host; /* Fraction for host entries */ 220 } nce_cache_reclaim_t; 221 222 /* When SAP is greater than zero address appears before SAP */ 223 #define NCE_LL_ADDR_OFFSET(ill) (((ill)->ill_sap_length) < 0 ? \ 224 (sizeof (dl_unitdata_req_t)) : \ 225 ((sizeof (dl_unitdata_req_t)) + (ABS((ill)->ill_sap_length)))) 226 227 #define NCE_LL_SAP_OFFSET(ill) (((ill)->ill_sap_length) < 0 ? \ 228 ((sizeof (dl_unitdata_req_t)) + ((ill)->ill_phys_addr_length)) : \ 229 (sizeof (dl_unitdata_req_t))) 230 231 #ifdef _BIG_ENDIAN 232 #define NCE_LL_SAP_COPY(ill, mp) \ 233 { \ 234 size_t abs_sap_len = ABS((ill)->ill_sap_length); \ 235 if (abs_sap_len > 0) { \ 236 ASSERT(abs_sap_len <= sizeof (uint32_t)); \ 237 ASSERT((mp)->b_rptr + NCE_LL_SAP_OFFSET(ill) + \ 238 abs_sap_len <= ((mp)->b_wptr)); \ 239 bcopy((uint8_t *)&(ill)->ill_sap + sizeof (ill->ill_sap) - \ 240 abs_sap_len, \ 241 ((mp)->b_rptr + NCE_LL_SAP_OFFSET(ill)), \ 242 abs_sap_len); \ 243 } \ 244 } 245 #else 246 #define NCE_LL_SAP_COPY(ill, mp) \ 247 { \ 248 size_t abs_sap_len = ABS((ill)->ill_sap_length); \ 249 if (abs_sap_len > 0) { \ 250 uint32_t abs_sap_len = ABS((ill)->ill_sap_length); \ 251 ASSERT(abs_sap_len <= sizeof (uint32_t)); \ 252 ASSERT((mp)->b_rptr + NCE_LL_SAP_OFFSET(ill) + \ 253 abs_sap_len <= ((mp)->b_wptr)); \ 254 bcopy(&((ill)->ill_sap), \ 255 ((mp)->b_rptr + NCE_LL_SAP_OFFSET(ill)), \ 256 abs_sap_len); \ 257 } \ 258 } 259 #endif 260 261 /* 262 * Exclusive-or the 6 bytes that are likely to contain the MAC 263 * address. Assumes table_size does not exceed 256. 264 * Assumes EUI-64 format for good hashing. 265 */ 266 #define NCE_ADDR_HASH_V6(addr, table_size) \ 267 (((addr).s6_addr8[8] ^ (addr).s6_addr8[9] ^ \ 268 (addr).s6_addr8[10] ^ (addr).s6_addr8[13] ^ \ 269 (addr).s6_addr8[14] ^ (addr).s6_addr8[15]) % (table_size)) 270 271 extern void ndp_cache_count(nce_t *, char *); 272 extern void ndp_cache_reclaim(nce_t *, char *); 273 extern void ndp_delete(nce_t *); 274 extern void ndp_delete_per_ill(nce_t *, uchar_t *); 275 extern void ndp_fastpath_flush(nce_t *, char *); 276 extern boolean_t ndp_fastpath_update(nce_t *, void *); 277 extern nd_opt_hdr_t *ndp_get_option(nd_opt_hdr_t *, int, int); 278 extern void ndp_inactive(nce_t *); 279 extern void ndp_input(ill_t *, mblk_t *); 280 extern nce_t *ndp_lookup_v6(ill_t *, const in6_addr_t *, boolean_t); 281 extern nce_t *ndp_lookup_v4(ill_t *, const in_addr_t *, boolean_t); 282 extern int ndp_lookup_then_add(ill_t *, uchar_t *, const void *, 283 const void *, const void *, uint32_t, uint16_t, 284 uint16_t, nce_t **, mblk_t *, mblk_t *); 285 extern int ndp_mcastreq(ill_t *, const in6_addr_t *, uint32_t, uint32_t, 286 mblk_t *); 287 extern int ndp_noresolver(ill_t *, const in6_addr_t *); 288 extern void ndp_process(nce_t *, uchar_t *, uint32_t, boolean_t); 289 extern int ndp_query(ill_t *, lif_nd_req_t *); 290 extern int ndp_report(queue_t *, mblk_t *, caddr_t, cred_t *); 291 extern int ndp_resolver(ill_t *, const in6_addr_t *, mblk_t *, zoneid_t); 292 extern int ndp_sioc_update(ill_t *, lif_nd_req_t *); 293 extern boolean_t ndp_verify_optlen(nd_opt_hdr_t *, int); 294 extern void ndp_timer(void *); 295 extern void ndp_walk(ill_t *, pfi_t, void *); 296 extern void ndp_walk_common(ndp_g_t *, ill_t *, pfi_t, 297 void *, boolean_t); 298 extern int ndp_add(ill_t *, uchar_t *, const void *, 299 const void *, const void *, 300 uint32_t, uint16_t, uint16_t, nce_t **, mblk_t *, mblk_t *); 301 extern void nce_resolv_failed(nce_t *); 302 extern void arp_resolv_failed(nce_t *); 303 extern void nce_fastpath_list_add(nce_t *); 304 extern void nce_fastpath_list_delete(nce_t *); 305 extern void nce_fastpath_list_dispatch(ill_t *, 306 boolean_t (*)(nce_t *, void *), void *); 307 extern void nce_queue_mp_common(nce_t *, mblk_t *, boolean_t); 308 extern void ndp_flush_qd_mp(nce_t *); 309 extern nce_t *nce_reinit(nce_t *); 310 311 #ifdef NCE_DEBUG 312 extern void nce_trace_inactive(nce_t *); 313 extern void nce_trace_ref(nce_t *); 314 extern void nce_untrace_ref(nce_t *); 315 extern int nce_thread_exit(nce_t *, caddr_t); 316 #endif 317 318 #endif /* _KERNEL */ 319 320 #ifdef __cplusplus 321 } 322 #endif 323 324 #endif /* _INET_IP_NDP_H */ 325