xref: /illumos-gate/usr/src/uts/common/inet/ip_ndp.h (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 2009 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 #include <sys/mutex.h>
30 #include <sys/stream.h>
31 #include <netinet/in.h>
32 #include <netinet/icmp6.h>
33 #include <inet/ip.h>
34 #include <inet/ip2mac.h>
35 
36 /*
37  * Internal definitions for the kernel implementation of the IPv6
38  * Neighbor Discovery Protocol (NDP).
39  */
40 
41 #ifdef	__cplusplus
42 extern "C" {
43 #endif
44 
45 #ifdef _KERNEL
46 #define	NCE_TABLE_SIZE	256
47 /*
48  * callbacks set up with ip2mac interface, waiting for result
49  * of neighbor resolution.
50  */
51 typedef struct nce_cb_s {
52 	list_node_t		nce_cb_node;
53 	void			*nce_cb_id;
54 	uint32_t		nce_cb_flags;
55 	ip2mac_callback_t	*nce_cb_func;
56 	void			*nce_cb_arg;
57 } nce_cb_t;
58 
59 #define	NCE_CB_DISPATCHED	0x00000001
60 
61 /*
62  * NDP Cache Entry
63  */
64 typedef struct nce_s {
65 	struct	nce_s	*nce_next;	/* Hash chain next pointer */
66 	struct	nce_s	**nce_ptpn;	/* Pointer to previous next */
67 	struct 	ill_s	*nce_ill;	/* Associated ill */
68 	uint16_t	nce_flags;	/* See below */
69 	uint16_t	nce_state;	/* See reachability states in if.h */
70 	int16_t		nce_pcnt;	/* Probe counter */
71 	uint16_t	nce_rcnt;	/* Retransmit counter */
72 	in6_addr_t	nce_addr;	/* address of the nighbor */
73 	in6_addr_t	nce_mask;	/* If not all ones, mask allows an */
74 	    /* entry  to respond to requests for a group of addresses, for */
75 	    /* instantance multicast addresses				   */
76 	in6_addr_t	nce_extract_mask; /* For mappings */
77 	uint32_t	nce_ll_extract_start;	/* For mappings */
78 #define	nce_first_mp_to_free	nce_fp_mp
79 	mblk_t		*nce_fp_mp;	/* link layer fast path mp */
80 	mblk_t		*nce_res_mp;	/* DL_UNITDATA_REQ */
81 	mblk_t		*nce_qd_mp;	/* Head outgoing queued packets */
82 #define	nce_last_mp_to_free	nce_qd_mp
83 	mblk_t		*nce_timer_mp;	/* NDP timer mblk */
84 	mblk_t		*nce_mp;	/* mblk we are in, last to be freed */
85 	uint64_t	nce_last;	/* Time last reachable in msec */
86 	uint32_t	nce_refcnt;	/* nce active usage count */
87 	kmutex_t	nce_lock;	/* See comments on top for what */
88 					/* this field protects */
89 	int		nce_unsolicit_count; /* Unsolicited Adv count */
90 	struct nce_s	*nce_fastpath;	/* for fastpath list */
91 	timeout_id_t	nce_timeout_id;
92 	uchar_t		nce_ipversion;	/* IPv4(ARP)/IPv6(NDP) version */
93 	uint_t		nce_defense_count;	/* number of NDP conflicts */
94 	uint_t		nce_defense_time;	/* last time defended (secs) */
95 	uint64_t	nce_init_time;  /* time when it was set to ND_INITIAL */
96 	boolean_t	nce_trace_disable;	/* True when alloc fails */
97 	list_t		nce_cb;
98 	uint_t		nce_cb_walker_cnt;
99 	uint_t		nce_ipif_cnt;	/* number of ipifs with the nce_addr */
100 					/* as their local address */
101 } nce_t;
102 
103 /*
104  * The ndp_g_t structure contains protocol specific information needed
105  * to synchronize and manage neighbor cache entries for IPv4 and IPv6.
106  * There are 2 such structures, ips_ndp4 and ips_ndp6.
107  * ips_ndp6 contains the data structures needed for IPv6 Neighbor Discovery.
108  * ips_ndp4 has IPv4 link layer info in its nce_t structures
109  * Note that the nce_t is not currently used as the arp cache itself;
110  * it is used for the following purposes:
111  *   - queue packets in nce_qd_mp while waiting for arp resolution to complete
112  *   - nce_{res, fp}_mp are used to track DL_UNITDATA request/responses.
113  *   - track state of ARP resolution in the nce_state;
114  *
115  * Locking notes:
116  * ndp_g_lock protects neighbor cache tables access and
117  * insertion/removal of cache entries into/from these tables.
118  * nce_lock protects nce_pcnt, nce_rcnt, nce_qd_mp nce_state, nce_res_mp,
119  * nce_refcnt, nce_last, and nce_cb_walker_cnt.
120  * nce_refcnt is incremented for every ire pointing to this nce and
121  * every time ndp_lookup() finds an nce.
122  * Should there be a need to obtain nce_lock and ndp_g_lock, ndp_g_lock is
123  * acquired first.
124  * To avoid becoming exclusive when deleting NCEs, ndp_walk() routine holds
125  * the ndp_g_lock (i.e global lock) and marks NCEs to be deleted with
126  * NCE_F_CONDEMNED.  When all active users of such NCEs are gone the walk
127  * routine passes a list for deletion to nce_ire_delete_list().
128  *
129  * When the link-layer address of some onlink host changes, ARP will send
130  * an AR_CN_ANNOUNCE message to ip so that stale neighbor-cache
131  * information will not get used. This message is processed in ip_arp_news()
132  * by walking the nce list, and updating as appropriate. The ndp_g_hw_change
133  * flag is set by ip_arp_news() to notify nce_t users that ip_arp_news() is
134  * in progress.
135  */
136 typedef	struct ndp_g_s {
137 	kmutex_t	ndp_g_lock;	/* Lock protecting  cache hash table */
138 	nce_t		*nce_mask_entries;	/* mask not all ones */
139 	nce_t		*nce_hash_tbl[NCE_TABLE_SIZE];
140 	int		ndp_g_walker; /* # of active thread walking hash list */
141 	boolean_t	ndp_g_walker_cleanup; /* true implies defer deletion. */
142 	int		ndp_g_hw_change; /* non-zero if nce flush in progress */
143 } ndp_g_t;
144 
145 #define	NDP_HW_CHANGE_INCR(ndp) {		\
146 	mutex_enter(&(ndp)->ndp_g_lock);	\
147 	(ndp)->ndp_g_hw_change++;		\
148 	mutex_exit(&(ndp)->ndp_g_lock);		\
149 }
150 
151 #define	NDP_HW_CHANGE_DECR(ndp) {		\
152 	mutex_enter(&(ndp)->ndp_g_lock);	\
153 	(ndp)->ndp_g_hw_change--;		\
154 	mutex_exit(&(ndp)->ndp_g_lock);		\
155 }
156 
157 /* nce_flags  */
158 #define	NCE_F_PERMANENT		0x1
159 #define	NCE_F_MAPPING		0x2
160 #define	NCE_F_ISROUTER		0x4
161 /*	unused			0x8 */
162 #define	NCE_F_NONUD		0x10
163 #define	NCE_F_ANYCAST		0x20
164 #define	NCE_F_CONDEMNED		0x40
165 #define	NCE_F_UNSOL_ADV		0x80
166 #define	NCE_F_BCAST		0x100
167 
168 #define	NCE_EXTERNAL_FLAGS_MASK \
169 	(NCE_F_PERMANENT | NCE_F_MAPPING | NCE_F_ISROUTER | NCE_F_NONUD | \
170 	NCE_F_ANYCAST | NCE_F_UNSOL_ADV)
171 
172 /* State REACHABLE, STALE, DELAY or PROBE */
173 #define	NCE_ISREACHABLE(nce)			\
174 	(((((nce)->nce_state) >= ND_REACHABLE) &&	\
175 	((nce)->nce_state) <= ND_PROBE))
176 
177 /* NDP flags set in SOL/ADV requests */
178 #define	NDP_UNICAST		0x1
179 #define	NDP_ISROUTER		0x2
180 #define	NDP_SOLICITED		0x4
181 #define	NDP_ORIDE		0x8
182 #define	NDP_PROBE		0x10
183 
184 /* Number of packets queued in NDP for a neighbor */
185 #define	ND_MAX_Q		4
186 
187 
188 #ifdef DEBUG
189 #define	NCE_TRACE_REF(nce)		nce_trace_ref(nce)
190 #define	NCE_UNTRACE_REF(nce)		nce_untrace_ref(nce)
191 #else
192 #define	NCE_TRACE_REF(nce)
193 #define	NCE_UNTRACE_REF(nce)
194 #endif
195 
196 #define	NCE_REFHOLD(nce) {		\
197 	mutex_enter(&(nce)->nce_lock);	\
198 	(nce)->nce_refcnt++;		\
199 	ASSERT((nce)->nce_refcnt != 0);	\
200 	NCE_TRACE_REF(nce);		\
201 	mutex_exit(&(nce)->nce_lock);	\
202 }
203 
204 #define	NCE_REFHOLD_NOTR(nce) {		\
205 	mutex_enter(&(nce)->nce_lock);	\
206 	(nce)->nce_refcnt++;		\
207 	ASSERT((nce)->nce_refcnt != 0);	\
208 	mutex_exit(&(nce)->nce_lock);	\
209 }
210 
211 #define	NCE_REFHOLD_LOCKED(nce) {		\
212 	ASSERT(MUTEX_HELD(&(nce)->nce_lock));	\
213 	(nce)->nce_refcnt++;			\
214 	NCE_TRACE_REF(nce);			\
215 }
216 
217 /* nce_inactive destroys the mutex thus no mutex_exit is needed */
218 #define	NCE_REFRELE(nce) {		\
219 	mutex_enter(&(nce)->nce_lock);	\
220 	NCE_UNTRACE_REF(nce);		\
221 	ASSERT((nce)->nce_refcnt != 0);	\
222 	if (--(nce)->nce_refcnt == 0)	\
223 		ndp_inactive(nce);	\
224 	else {				\
225 		mutex_exit(&(nce)->nce_lock);\
226 	}				\
227 }
228 
229 #define	NCE_REFRELE_NOTR(nce) {		\
230 	mutex_enter(&(nce)->nce_lock);	\
231 	ASSERT((nce)->nce_refcnt != 0);	\
232 	if (--(nce)->nce_refcnt == 0)	\
233 		ndp_inactive(nce);	\
234 	else {				\
235 		mutex_exit(&(nce)->nce_lock);\
236 	}				\
237 }
238 
239 #define	NDP_RESTART_TIMER(nce, ms) {	\
240 	ASSERT(!MUTEX_HELD(&(nce)->nce_lock));				\
241 	if ((nce)->nce_timeout_id != 0) {				\
242 		/* Ok to untimeout bad id. we don't hold a lock. */	\
243 		(void) untimeout((nce)->nce_timeout_id);		\
244 	}								\
245 	mutex_enter(&(nce)->nce_lock);					\
246 	/* Don't start the timer if the nce has been deleted */		\
247 	if (!((nce)->nce_flags & NCE_F_CONDEMNED)) 			\
248 		nce->nce_timeout_id = timeout(ndp_timer, nce, 		\
249 		    MSEC_TO_TICK(ms) == 0 ? 1 : MSEC_TO_TICK(ms));	\
250 	mutex_exit(&(nce)->nce_lock);					\
251 }
252 
253 /* Structure for ndp_cache_count() */
254 typedef struct {
255 	int	ncc_total;	/* Total number of NCEs */
256 	int	ncc_host;	/* NCE entries without R bit set */
257 } ncc_cache_count_t;
258 
259 /*
260  * Structure of ndp_cache_reclaim().  Each field is a fraction i.e. 1 means
261  * reclaim all, N means reclaim 1/Nth of all entries, 0 means reclaim none.
262  */
263 typedef struct {
264 	int	ncr_host;	/* Fraction for host entries */
265 } nce_cache_reclaim_t;
266 
267 /*
268  * Structure for nce_delete_hw_changed; specifies an IPv4 address to link-layer
269  * address mapping.  Any route that has a cached copy of a mapping for that
270  * IPv4 address that doesn't match the given mapping must be purged.
271  */
272 typedef struct {
273 	ipaddr_t hwm_addr;	/* IPv4 address */
274 	uint_t hwm_hwlen;	/* Length of hardware address (may be 0) */
275 	uchar_t *hwm_hwaddr;	/* Pointer to new hardware address, if any */
276 } nce_hw_map_t;
277 
278 /* When SAP is greater than zero address appears before SAP */
279 #define	NCE_LL_ADDR_OFFSET(ill)	(((ill)->ill_sap_length) < 0 ? \
280 	(sizeof (dl_unitdata_req_t)) : \
281 	((sizeof (dl_unitdata_req_t)) + (ABS((ill)->ill_sap_length))))
282 
283 #define	NCE_LL_SAP_OFFSET(ill) (((ill)->ill_sap_length) < 0 ? \
284 	((sizeof (dl_unitdata_req_t)) + ((ill)->ill_phys_addr_length)) : \
285 	(sizeof (dl_unitdata_req_t)))
286 
287 #ifdef _BIG_ENDIAN
288 #define	NCE_LL_SAP_COPY(ill, mp) \
289 	{ \
290 	size_t abs_sap_len = ABS((ill)->ill_sap_length); \
291 	if (abs_sap_len > 0) { \
292 		ASSERT(abs_sap_len <= sizeof (uint32_t)); \
293 		ASSERT((mp)->b_rptr + NCE_LL_SAP_OFFSET(ill) + \
294 		    abs_sap_len <= ((mp)->b_wptr)); \
295 		bcopy((uint8_t *)&(ill)->ill_sap + sizeof (ill->ill_sap) - \
296 		    abs_sap_len, \
297 		    ((mp)->b_rptr + NCE_LL_SAP_OFFSET(ill)), \
298 		    abs_sap_len); \
299 	} \
300 	}
301 #else
302 #define	NCE_LL_SAP_COPY(ill, mp) \
303 	{ \
304 	size_t abs_sap_len = ABS((ill)->ill_sap_length); \
305 	if (abs_sap_len > 0) { \
306 		uint32_t abs_sap_len = ABS((ill)->ill_sap_length); \
307 		ASSERT(abs_sap_len <= sizeof (uint32_t)); \
308 		ASSERT((mp)->b_rptr + NCE_LL_SAP_OFFSET(ill) + \
309 		    abs_sap_len <= ((mp)->b_wptr)); \
310 		bcopy(&((ill)->ill_sap), \
311 		((mp)->b_rptr + NCE_LL_SAP_OFFSET(ill)), \
312 		abs_sap_len); \
313 	} \
314 	}
315 #endif
316 
317 /*
318  * Exclusive-or the 6 bytes that are likely to contain the MAC
319  * address. Assumes table_size does not exceed 256.
320  * Assumes EUI-64 format for good hashing.
321  */
322 #define	NCE_ADDR_HASH_V6(addr, table_size)				\
323 	(((addr).s6_addr8[8] ^ (addr).s6_addr8[9] ^			\
324 	(addr).s6_addr8[10] ^ (addr).s6_addr8[13] ^			\
325 	(addr).s6_addr8[14] ^ (addr).s6_addr8[15]) % (table_size))
326 
327 /* NDP Cache Entry Hash Table */
328 #define	NCE_TABLE_SIZE	256
329 
330 extern	void	ndp_cache_count(nce_t *, char *);
331 extern	void	ndp_cache_reclaim(nce_t *, char *);
332 extern	void	ndp_delete(nce_t *);
333 extern	void	ndp_delete_per_ill(nce_t *, uchar_t *);
334 extern	void	ndp_fastpath_flush(nce_t *, char  *);
335 extern	boolean_t ndp_fastpath_update(nce_t *, void  *);
336 extern	nd_opt_hdr_t *ndp_get_option(nd_opt_hdr_t *, int, int);
337 extern	void	ndp_inactive(nce_t *);
338 extern	void	ndp_input(ill_t *, mblk_t *, mblk_t *);
339 extern	boolean_t ndp_lookup_ipaddr(in_addr_t, netstack_t *);
340 extern	nce_t	*ndp_lookup_v6(ill_t *, boolean_t, const in6_addr_t *,
341     boolean_t);
342 extern	nce_t	*ndp_lookup_v4(ill_t *, const in_addr_t *, boolean_t);
343 extern	int	ndp_mcastreq(ill_t *, const in6_addr_t *, uint32_t, uint32_t,
344     mblk_t *);
345 extern	int	ndp_noresolver(ill_t *, const in6_addr_t *);
346 extern	void	ndp_process(nce_t *, uchar_t *, uint32_t, boolean_t);
347 extern	int	ndp_query(ill_t *, lif_nd_req_t *);
348 extern	int	ndp_resolver(ill_t *, const in6_addr_t *, mblk_t *, zoneid_t);
349 extern	int	ndp_sioc_update(ill_t *, lif_nd_req_t *);
350 extern	boolean_t	ndp_verify_optlen(nd_opt_hdr_t *, int);
351 extern	void	ndp_timer(void *);
352 extern	void	ndp_walk(ill_t *, pfi_t, void *, ip_stack_t *);
353 extern	void	ndp_walk_common(ndp_g_t *, ill_t *, pfi_t,
354     void *, boolean_t);
355 extern	boolean_t	ndp_restart_dad(nce_t *);
356 extern	void	ndp_do_recovery(ipif_t *);
357 extern	void	nce_resolv_failed(nce_t *);
358 extern	void	arp_resolv_failed(nce_t *);
359 extern	void	nce_fastpath_list_add(nce_t *);
360 extern	void	nce_fastpath_list_delete(nce_t *);
361 extern	void	nce_fastpath_list_dispatch(ill_t *,
362     boolean_t (*)(nce_t *, void  *), void *);
363 extern	void	nce_queue_mp_common(nce_t *, mblk_t *, boolean_t);
364 extern	void	nce_delete_hw_changed(nce_t *, void *);
365 extern	void	nce_fastpath(nce_t *);
366 extern	int	ndp_add_v6(ill_t *, uchar_t *, const in6_addr_t *,
367     const in6_addr_t *, const in6_addr_t *, uint32_t, uint16_t, uint16_t,
368     nce_t **);
369 extern	int	ndp_lookup_then_add_v6(ill_t *, boolean_t, uchar_t *,
370     const in6_addr_t *, const in6_addr_t *, const in6_addr_t *, uint32_t,
371     uint16_t, uint16_t, nce_t **);
372 extern	int	ndp_lookup_then_add_v4(ill_t *,
373     const in_addr_t *, uint16_t, nce_t **, nce_t *);
374 extern void	ip_ndp_resolve(nce_t *);
375 
376 #ifdef DEBUG
377 extern	void	nce_trace_ref(nce_t *);
378 extern	void	nce_untrace_ref(nce_t *);
379 #endif
380 
381 #endif	/* _KERNEL */
382 
383 #ifdef	__cplusplus
384 }
385 #endif
386 
387 #endif	/* _INET_IP_NDP_H */
388