| 1 | /*- |
| 2 | * SPDX-License-Identifier: BSD-2-Clause |
| 3 | * |
| 4 | * Copyright (c) 2004 Luigi Rizzo, Alessandro Cerri. All rights reserved. |
| 5 | * Copyright (c) 2004-2008 Qing Li. All rights reserved. |
| 6 | * Copyright (c) 2008 Kip Macy. All rights reserved. |
| 7 | * |
| 8 | * Redistribution and use in source and binary forms, with or without |
| 9 | * modification, are permitted provided that the following conditions |
| 10 | * are met: |
| 11 | * 1. Redistributions of source code must retain the above copyright |
| 12 | * notice, this list of conditions and the following disclaimer. |
| 13 | * 2. Redistributions in binary form must reproduce the above copyright |
| 14 | * notice, this list of conditions and the following disclaimer in the |
| 15 | * documentation and/or other materials provided with the distribution. |
| 16 | * |
| 17 | * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
| 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 20 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE |
| 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 27 | * SUCH DAMAGE. |
| 28 | */ |
| 29 | #include <sys/cdefs.h> |
| 30 | #ifndef	_NET_IF_LLATBL_H_ |
| 31 | #define	_NET_IF_LLATBL_H_ |
| 32 | |
| 33 | #include <sys/_eventhandler.h> |
| 34 | #include <sys/_rwlock.h> |
| 35 | #include <netinet/in.h> |
| 36 | #include <sys/epoch.h> |
| 37 | #include <sys/ck.h> |
| 38 | |
| 39 | struct ifnet; |
| 40 | struct sysctl_req; |
| 41 | struct rt_msghdr; |
| 42 | struct rt_addrinfo; |
| 43 | struct llentry; |
| 44 | CK_LIST_HEAD(llentries, llentry); |
| 45 | |
| 46 | #define	LLE_MAX_LINKHDR		24	/* Full IB header */ |
| 47 | /* |
| 48 | * Code referencing llentry must at least hold |
| 49 | * a shared lock |
| 50 | */ |
| 51 | struct llentry { |
| 52 | 	CK_LIST_ENTRY(llentry)	 lle_next; |
| 53 | 	union { |
| 54 | 		struct in_addr	addr4; |
| 55 | 		struct in6_addr	addr6; |
| 56 | 	} r_l3addr; |
| 57 | 	char			r_linkdata[LLE_MAX_LINKHDR]; /* L2 data */ |
| 58 | 	uint8_t			r_hdrlen;	/* length for LL header */ |
| 59 | 	uint8_t			r_family;	/* Upper layer proto family */ |
| 60 | 	uint8_t			spare0[2]; |
| 61 | 	uint16_t		r_flags;	/* LLE runtime flags */ |
| 62 | 	uint16_t		r_skip_req;	/* feedback from fast path */ |
| 63 | |
| 64 | 	struct lltable		 *lle_tbl; |
| 65 | 	struct llentries	 *lle_head; |
| 66 | 	void			(*lle_free)(struct llentry *); |
| 67 | 	struct mbuf		 *la_hold; |
| 68 | 	int			 la_numheld; /* # of packets currently held */ |
| 69 | 	time_t			 la_expire; |
| 70 | 	uint16_t		 la_flags; |
| 71 | 	uint16_t		 la_asked; |
| 72 | 	uint16_t		 la_preempt; |
| 73 | 	int16_t			 ln_state;	/* IPv6 has ND6_LLINFO_NOSTATE == -2 */ |
| 74 | 	uint16_t		 ln_router; |
| 75 | 	time_t			 ln_ntick; |
| 76 | 	time_t			lle_remtime;	/* Real time remaining */ |
| 77 | 	time_t			lle_hittime;	/* Time when r_skip_req was unset */ |
| 78 | 	int			 lle_refcnt; |
| 79 | 	char			*ll_addr;	/* link-layer address */ |
| 80 | 	CK_SLIST_HEAD(llentry_children_head,llentry)	lle_children;	/* child encaps */ |
| 81 | 	CK_SLIST_ENTRY(llentry)	lle_child_next;	/* child encaps */ |
| 82 | 	struct llentry		*lle_parent;	/* parent for a child */ |
| 83 | |
| 84 | 	CK_LIST_ENTRY(llentry)	lle_chain;	/* chain of deleted items */ |
| 85 | 	struct callout		lle_timer; |
| 86 | 	struct rwlock		 lle_lock; |
| 87 | 	struct mtx		req_mtx; |
| 88 | 	struct epoch_context lle_epoch_ctx; |
| 89 | }; |
| 90 | |
| 91 | #define	LLE_WLOCK(lle)		rw_wlock(&(lle)->lle_lock) |
| 92 | #define	LLE_RLOCK(lle)		rw_rlock(&(lle)->lle_lock) |
| 93 | #define	LLE_WUNLOCK(lle)	rw_wunlock(&(lle)->lle_lock) |
| 94 | #define	LLE_RUNLOCK(lle)	rw_runlock(&(lle)->lle_lock) |
| 95 | #define	LLE_DOWNGRADE(lle)	rw_downgrade(&(lle)->lle_lock) |
| 96 | #define	LLE_TRY_UPGRADE(lle)	rw_try_upgrade(&(lle)->lle_lock) |
| 97 | #define	LLE_LOCK_INIT(lle)	rw_init_flags(&(lle)->lle_lock, "lle", RW_DUPOK) |
| 98 | #define	LLE_LOCK_DESTROY(lle)	rw_destroy(&(lle)->lle_lock) |
| 99 | #define	LLE_WLOCK_ASSERT(lle)	rw_assert(&(lle)->lle_lock, RA_WLOCKED) |
| 100 | |
| 101 | #define	LLE_REQ_INIT(lle)	mtx_init(&(lle)->req_mtx, "lle req", \ |
| 102 | 	NULL, MTX_DEF) |
| 103 | #define	LLE_REQ_DESTROY(lle)	mtx_destroy(&(lle)->req_mtx) |
| 104 | #define	LLE_REQ_LOCK(lle)	mtx_lock(&(lle)->req_mtx) |
| 105 | #define	LLE_REQ_UNLOCK(lle)	mtx_unlock(&(lle)->req_mtx) |
| 106 | |
| 107 | #define LLE_IS_VALID(lle)	(((lle) != NULL) && ((lle) != (void *)-1)) |
| 108 | |
| 109 | #define	LLE_SF(_fam, _flags)	(((_flags) & 0xFFFF) | ((_fam) << 16)) |
| 110 | |
| 111 | #define	LLE_ADDREF(lle) do {					\ |
| 112 | 	LLE_WLOCK_ASSERT(lle);					\ |
| 113 | 	KASSERT((lle)->lle_refcnt >= 0,				\ |
| 114 | 	 ("negative refcnt %d on lle %p",			\ |
| 115 | 	 (lle)->lle_refcnt, (lle)));				\ |
| 116 | 	(lle)->lle_refcnt++;					\ |
| 117 | } while (0) |
| 118 | |
| 119 | #define	LLE_REMREF(lle)	do {					\ |
| 120 | 	LLE_WLOCK_ASSERT(lle);					\ |
| 121 | 	KASSERT((lle)->lle_refcnt > 0,				\ |
| 122 | 	 ("bogus refcnt %d on lle %p",			\ |
| 123 | 	 (lle)->lle_refcnt, (lle)));				\ |
| 124 | 	(lle)->lle_refcnt--;					\ |
| 125 | } while (0) |
| 126 | |
| 127 | #define	LLE_FREE_LOCKED(lle) do {				\ |
| 128 | 	if ((lle)->lle_refcnt == 1)				\ |
| 129 | 		(lle)->lle_free(lle);				\ |
| 130 | 	else {							\ |
| 131 | 		LLE_REMREF(lle);				\ |
| 132 | 		LLE_WUNLOCK(lle);				\ |
| 133 | 	}							\ |
| 134 | 	/* guard against invalid refs */			\ |
| 135 | 	(lle) = NULL;						\ |
| 136 | } while (0) |
| 137 | |
| 138 | #define	LLE_FREE(lle) do {					\ |
| 139 | 	LLE_WLOCK(lle);						\ |
| 140 | 	LLE_FREE_LOCKED(lle);					\ |
| 141 | } while (0) |
| 142 | |
| 143 | typedef	struct llentry *(llt_lookup_t)(struct lltable *, u_int flags, |
| 144 | const struct sockaddr *l3addr); |
| 145 | typedef	struct llentry *(llt_alloc_t)(struct lltable *, u_int flags, |
| 146 | const struct sockaddr *l3addr); |
| 147 | typedef	void (llt_delete_t)(struct lltable *, struct llentry *); |
| 148 | typedef void (llt_prefix_free_t)(struct lltable *, |
| 149 | const struct sockaddr *addr, const struct sockaddr *mask, u_int flags); |
| 150 | typedef int (llt_dump_entry_t)(struct lltable *, struct llentry *, |
| 151 | struct sysctl_req *); |
| 152 | typedef uint32_t (llt_hash_t)(const struct llentry *, uint32_t); |
| 153 | typedef int (llt_match_prefix_t)(const struct sockaddr *, |
| 154 | const struct sockaddr *, u_int, struct llentry *); |
| 155 | typedef void (llt_free_entry_t)(struct lltable *, struct llentry *); |
| 156 | typedef void (llt_fill_sa_entry_t)(const struct llentry *, struct sockaddr *); |
| 157 | typedef void (llt_free_tbl_t)(struct lltable *); |
| 158 | typedef int (llt_link_entry_t)(struct lltable *, struct llentry *); |
| 159 | typedef int (llt_unlink_entry_t)(struct llentry *); |
| 160 | typedef void (llt_mark_used_t)(struct llentry *); |
| 161 | typedef void (llt_post_resolved_t)(struct lltable *, struct llentry *); |
| 162 | |
| 163 | typedef int (llt_foreach_cb_t)(struct lltable *, struct llentry *, void *); |
| 164 | typedef int (llt_foreach_entry_t)(struct lltable *, llt_foreach_cb_t *, void *); |
| 165 | typedef bool (llt_match_cb_t)(struct lltable *, struct llentry *, void *); |
| 166 | |
| 167 | struct lltable { |
| 168 | 	SLIST_ENTRY(lltable)	llt_link; |
| 169 | 	sa_family_t		llt_af; |
| 170 | 	uint8_t			llt_flags; |
| 171 | 	uint8_t			llt_spare[2]; |
| 172 | 	int			llt_hsize; |
| 173 | 	int			llt_entries; |
| 174 | 	int			llt_maxentries; |
| 175 | 	struct llentries	*lle_head; |
| 176 | 	struct ifnet		*llt_ifp; |
| 177 | |
| 178 | 	llt_lookup_t		*llt_lookup; |
| 179 | 	llt_alloc_t		*llt_alloc_entry; |
| 180 | 	llt_delete_t		*llt_delete_entry; |
| 181 | 	llt_prefix_free_t	*llt_prefix_free; |
| 182 | 	llt_dump_entry_t	*llt_dump_entry; |
| 183 | 	llt_hash_t		*llt_hash; |
| 184 | 	llt_match_prefix_t	*llt_match_prefix; |
| 185 | 	llt_free_entry_t	*llt_free_entry; |
| 186 | 	llt_foreach_entry_t	*llt_foreach_entry; |
| 187 | 	llt_link_entry_t	*llt_link_entry; |
| 188 | 	llt_unlink_entry_t	*llt_unlink_entry; |
| 189 | 	llt_fill_sa_entry_t	*llt_fill_sa_entry; |
| 190 | 	llt_free_tbl_t		*llt_free_tbl; |
| 191 | 	llt_mark_used_t		*llt_mark_used; |
| 192 | 	llt_post_resolved_t	*llt_post_resolved; |
| 193 | }; |
| 194 | |
| 195 | MALLOC_DECLARE(M_LLTABLE); |
| 196 | |
| 197 | /* |
| 198 | * LLtable flags |
| 199 | */ |
| 200 | #define	LLT_ADDEDPROXY	0x01	/* added a proxy llentry */ |
| 201 | |
| 202 | /* |
| 203 | * LLentry flags |
| 204 | */ |
| 205 | #define	LLE_DELETED	0x0001	/* entry must be deleted */ |
| 206 | #define	LLE_STATIC	0x0002	/* entry is static */ |
| 207 | #define	LLE_IFADDR	0x0004	/* entry is interface addr */ |
| 208 | #define	LLE_VALID	0x0008	/* ll_addr is valid */ |
| 209 | #define	LLE_REDIRECT	0x0010	/* installed by redirect; has host rtentry */ |
| 210 | #define	LLE_PUB		0x0020	/* publish entry ??? */ |
| 211 | #define	LLE_LINKED	0x0040	/* linked to lookup structure */ |
| 212 | #define	LLE_CHILD	0x0080	/* Child LLE storing different AF encap */ |
| 213 | /* LLE request flags */ |
| 214 | #define	LLE_EXCLUSIVE	0x2000	/* return lle xlocked */ |
| 215 | #define	LLE_UNLOCKED	0x4000	/* return lle unlocked */ |
| 216 | #define	LLE_ADDRONLY	0x4000	/* return lladdr instead of full header */ |
| 217 | #define	LLE_CREATE	0x8000	/* hint to avoid lle lookup */ |
| 218 | |
| 219 | /* LLE flags used by fastpath code */ |
| 220 | #define	RLLE_VALID	0x0001		/* entry is valid */ |
| 221 | #define	RLLE_IFADDR	LLE_IFADDR	/* entry is ifaddr */ |
| 222 | |
| 223 | #define LLATBL_HASH(key, mask) \ |
| 224 | 	(((((((key >> 8) ^ key) >> 8) ^ key) >> 8) ^ key) & mask) |
| 225 | |
| 226 | struct lltable *lltable_allocate_htbl(uint32_t hsize); |
| 227 | void		lltable_free(struct lltable *); |
| 228 | void		lltable_link(struct lltable *llt); |
| 229 | void		lltable_prefix_free(int, struct sockaddr *, |
| 230 | 		 struct sockaddr *, u_int); |
| 231 | int		lltable_sysctl_dumparp(int, struct sysctl_req *); |
| 232 | size_t		lltable_append_entry_queue(struct llentry *, |
| 233 | 		 struct mbuf *, size_t); |
| 234 | |
| 235 | struct lltable *in_lltable_get(struct ifnet *ifp); |
| 236 | struct lltable *in6_lltable_get(struct ifnet *ifp); |
| 237 | struct lltable *lltable_get(struct ifnet *ifp, int family); |
| 238 | |
| 239 | size_t		llentry_free(struct llentry *); |
| 240 | |
| 241 | /* helper functions */ |
| 242 | size_t lltable_drop_entry_queue(struct llentry *); |
| 243 | void lltable_set_entry_addr(struct ifnet *ifp, struct llentry *lle, |
| 244 | const char *linkhdr, size_t linkhdrsize, int lladdr_off); |
| 245 | int lltable_try_set_entry_addr(struct ifnet *ifp, struct llentry *lle, |
| 246 | const char *linkhdr, size_t linkhdrsize, int lladdr_off); |
| 247 | |
| 248 | int lltable_calc_llheader(struct ifnet *ifp, int family, char *lladdr, |
| 249 | char *buf, size_t *bufsize, int *lladdr_off); |
| 250 | void lltable_update_ifaddr(struct lltable *llt); |
| 251 | struct llentry *lltable_alloc_entry(struct lltable *llt, u_int flags, |
| 252 | const struct sockaddr *l4addr); |
| 253 | void lltable_free_entry(struct lltable *llt, struct llentry *lle); |
| 254 | int lltable_delete_addr(struct lltable *llt, u_int flags, |
| 255 | const struct sockaddr *l3addr); |
| 256 | int lltable_link_entry(struct lltable *llt, struct llentry *lle); |
| 257 | int lltable_unlink_entry(struct lltable *llt, struct llentry *lle); |
| 258 | void lltable_link_child_entry(struct llentry *parent_lle, struct llentry *child_lle); |
| 259 | void lltable_unlink_child_entry(struct llentry *child_lle); |
| 260 | void lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa); |
| 261 | struct ifnet *lltable_get_ifp(const struct lltable *llt); |
| 262 | int lltable_get_af(const struct lltable *llt); |
| 263 | |
| 264 | bool lltable_acquire_wlock(struct ifnet *ifp, struct llentry *lle); |
| 265 | |
| 266 | int lltable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, |
| 267 | void *farg); |
| 268 | void lltable_delete_conditional(struct lltable *llt, llt_match_cb_t *func, |
| 269 | void *farg); |
| 270 | |
| 271 | /* |
| 272 | * Generic link layer address lookup function. |
| 273 | */ |
| 274 | static __inline struct llentry * |
| 275 | lla_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3addr) |
| 276 | { |
| 277 | |
| 278 | 	return (llt->llt_lookup(llt, flags, l3addr)); |
| 279 | } |
| 280 | |
| 281 | void llentry_request_feedback(struct llentry *lle); |
| 282 | void llentry_mark_used(struct llentry *lle); |
| 283 | time_t llentry_get_hittime(struct llentry *lle); |
| 284 | int llentry_get_upper_family(const struct llentry *lle, int default_family); |
| 285 | |
| 286 | /* |
| 287 | * Notify the LLE code that the entry was used by datapath. |
| 288 | */ |
| 289 | static __inline void |
| 290 | llentry_provide_feedback(struct llentry *lle) |
| 291 | { |
| 292 | |
| 293 | 	if (__predict_true(lle->r_skip_req == 0)) |
| 294 | 		return; |
| 295 | 	llentry_mark_used(lle); |
| 296 | } |
| 297 | struct llentry *llentry_lookup_family(struct llentry *lle, int family); |
| 298 | |
| 299 | int		lla_rt_output(struct rt_msghdr *, struct rt_addrinfo *); |
| 300 | |
| 301 | enum { |
| 302 | 	LLENTRY_RESOLVED, |
| 303 | 	LLENTRY_TIMEDOUT, |
| 304 | 	LLENTRY_DELETED, |
| 305 | 	LLENTRY_EXPIRED, |
| 306 | }; |
| 307 | typedef void (*lle_event_fn)(void *, struct llentry *, int); |
| 308 | EVENTHANDLER_DECLARE(lle_event, lle_event_fn); |
| 309 | #endif /* _NET_IF_LLATBL_H_ */ |