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