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