xref: /titanic_50/usr/src/uts/common/inet/ip_ndp.h (revision e4163c9bf1c1d30987c9216473236d730dc3c3a9)
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