xref: /freebsd/sys/netpfil/ipfw/nat64/nat64lsn.h (revision 1c05a6ea6b849ff95e539c31adea887c644a6a01)
1 /*-
2  * Copyright (c) 2015 Yandex LLC
3  * Copyright (c) 2015 Alexander V. Chernikov <melifaro@FreeBSD.org>
4  * Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
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 THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30 
31 #ifndef	_IP_FW_NAT64LSN_H_
32 #define	_IP_FW_NAT64LSN_H_
33 
34 #define	NAT64_CHUNK_SIZE_BITS	6	/* 64 ports */
35 #define	NAT64_CHUNK_SIZE	(1 << NAT64_CHUNK_SIZE_BITS)
36 
37 #define	NAT64_MIN_PORT		1024
38 #define	NAT64_MIN_CHUNK		(NAT64_MIN_PORT >> NAT64_CHUNK_SIZE_BITS)
39 
40 struct st_ptr {
41 	uint8_t			idx;	/* index in nh->pg_ptr array.
42 					 * NOTE: it starts from 1.
43 					 */
44 	uint8_t			off;
45 };
46 #define	NAT64LSN_MAXPGPTR	((1 << (sizeof(uint8_t) * NBBY)) - 1)
47 #define	NAT64LSN_PGPTRMASKBITS	(sizeof(uint64_t) * NBBY)
48 #define	NAT64LSN_PGPTRNMASK	(roundup(NAT64LSN_MAXPGPTR,	\
49     NAT64LSN_PGPTRMASKBITS) / NAT64LSN_PGPTRMASKBITS)
50 
51 struct nat64lsn_portgroup;
52 /* sizeof(struct nat64lsn_host) = 64 + 64x2 + 8x8 = 256 bytes */
53 struct nat64lsn_host {
54 	struct rwlock	h_lock;		/* Host states lock */
55 
56 	struct in6_addr	addr;
57 	struct nat64lsn_host	*next;
58 	uint16_t	timestamp;	/* Last altered */
59 	uint16_t	hsize;		/* ports hash size */
60 	uint16_t	pg_used;	/* Number of portgroups used */
61 #define	NAT64LSN_REMAININGPG	8	/* Number of remaining PG before
62 					 * requesting of new chunk of indexes.
63 					 */
64 	uint16_t	pg_allocated;	/* Number of portgroups indexes
65 					 * allocated.
66 					 */
67 #define	NAT64LSN_HSIZE	64
68 	struct st_ptr	phash[NAT64LSN_HSIZE]; /* XXX: hardcoded size */
69 	/*
70 	 * PG indexes are stored in chunks with 32 elements.
71 	 * The maximum count is limited to 255 due to st_ptr->idx is uint8_t.
72 	 */
73 #define	NAT64LSN_PGIDX_CHUNK	32
74 #define	NAT64LSN_PGNIDX		(roundup(NAT64LSN_MAXPGPTR, \
75     NAT64LSN_PGIDX_CHUNK) / NAT64LSN_PGIDX_CHUNK)
76 	struct nat64lsn_portgroup **pg_ptr[NAT64LSN_PGNIDX]; /* PG indexes */
77 };
78 
79 #define	NAT64_RLOCK_ASSERT(h)	rw_assert(&(h)->h_lock, RA_RLOCKED)
80 #define	NAT64_WLOCK_ASSERT(h)	rw_assert(&(h)->h_lock, RA_WLOCKED)
81 
82 #define	NAT64_RLOCK(h)		rw_rlock(&(h)->h_lock)
83 #define	NAT64_RUNLOCK(h)	rw_runlock(&(h)->h_lock)
84 #define	NAT64_WLOCK(h)		rw_wlock(&(h)->h_lock)
85 #define	NAT64_WUNLOCK(h)	rw_wunlock(&(h)->h_lock)
86 #define	NAT64_LOCK(h)		NAT64_WLOCK(h)
87 #define	NAT64_UNLOCK(h)		NAT64_WUNLOCK(h)
88 #define	NAT64_LOCK_INIT(h) do {			\
89 	rw_init(&(h)->h_lock, "NAT64 host lock");	\
90 	} while (0)
91 
92 #define	NAT64_LOCK_DESTROY(h) do {			\
93 	rw_destroy(&(h)->h_lock);			\
94 	} while (0)
95 
96 /* Internal proto index */
97 #define	NAT_PROTO_TCP	1
98 #define	NAT_PROTO_UDP	2
99 #define	NAT_PROTO_ICMP	3
100 
101 #define	NAT_MAX_PROTO	4
102 extern uint8_t nat64lsn_rproto_map[NAT_MAX_PROTO];
103 
104 VNET_DECLARE(uint16_t, nat64lsn_eid);
105 #define	V_nat64lsn_eid		VNET(nat64lsn_eid)
106 #define	IPFW_TLV_NAT64LSN_NAME	IPFW_TLV_EACTION_NAME(V_nat64lsn_eid)
107 
108 /* Timestamp macro */
109 #define	_CT		((int)time_uptime % 65536)
110 #define	SET_AGE(x)	(x) = _CT
111 #define	GET_AGE(x)	((_CT >= (x)) ? _CT - (x) :	\
112 	(int)65536 + _CT - (x))
113 
114 #ifdef __LP64__
115 /* ffsl() is capable of checking 64-bit ints */
116 #define	_FFS64
117 #endif
118 
119 /* 16 bytes */
120 struct nat64lsn_state {
121 	union {
122 		struct {
123 			in_addr_t	faddr;	/* Remote IPv4 address */
124 			uint16_t	fport;	/* Remote IPv4 port */
125 			uint16_t	lport;	/* Local IPv6 port */
126 		}s;
127 		uint64_t		hkey;
128 	} u;
129 	uint8_t		nat_proto;
130 	uint8_t		flags;
131 	uint16_t	timestamp;
132 	struct st_ptr	cur; /* Index of portgroup in nat64lsn_host */
133 	struct st_ptr	next; /* Next entry index */
134 };
135 
136 /*
137  * 1024+32 bytes per 64 states, used to store state
138  * AND for outside-in state lookup
139  */
140 struct nat64lsn_portgroup {
141 	struct nat64lsn_host	*host;	/* IPv6 source host info */
142 	in_addr_t		aaddr;	/* Alias addr, network format */
143 	uint16_t		aport;	/* Base port */
144 	uint16_t		timestamp;
145 	uint8_t			nat_proto;
146 	uint8_t			spare[3];
147 	uint32_t		idx;
148 #ifdef _FFS64
149 	uint64_t		freemask;	/* Mask of free entries */
150 #else
151 	uint32_t		freemask[2];	/* Mask of free entries */
152 #endif
153 	struct nat64lsn_state	states[NAT64_CHUNK_SIZE]; /* State storage */
154 };
155 #ifdef _FFS64
156 #define	PG_MARK_BUSY_IDX(_pg, _idx)	(_pg)->freemask &= ~((uint64_t)1<<(_idx))
157 #define	PG_MARK_FREE_IDX(_pg, _idx)	(_pg)->freemask |= ((uint64_t)1<<(_idx))
158 #define	PG_IS_FREE_IDX(_pg, _idx)	((_pg)->freemask & ((uint64_t)1<<(_idx)))
159 #define	PG_IS_BUSY_IDX(_pg, _idx)	(PG_IS_FREE_IDX(_pg, _idx) == 0)
160 #define	PG_GET_FREE_IDX(_pg)		(ffsll((_pg)->freemask))
161 #define	PG_IS_EMPTY(_pg)		(((_pg)->freemask + 1) == 0)
162 #else
163 #define	PG_MARK_BUSY_IDX(_pg, _idx)	\
164 	(_pg)->freemask[(_idx) / 32] &= ~((u_long)1<<((_idx) % 32))
165 #define	PG_MARK_FREE_IDX(_pg, _idx)	\
166 	(_pg)->freemask[(_idx) / 32] |= ((u_long)1<<((_idx)  % 32))
167 #define	PG_IS_FREE_IDX(_pg, _idx)	\
168 	((_pg)->freemask[(_idx) / 32] & ((u_long)1<<((_idx) % 32)))
169 #define	PG_IS_BUSY_IDX(_pg, _idx)	(PG_IS_FREE_IDX(_pg, _idx) == 0)
170 #define	PG_GET_FREE_IDX(_pg)		_pg_get_free_idx(_pg)
171 #define	PG_IS_EMPTY(_pg)		\
172 	((((_pg)->freemask[0] + 1) == 0 && ((_pg)->freemask[1] + 1) == 0))
173 
174 static inline int
175 _pg_get_free_idx(const struct nat64lsn_portgroup *pg)
176 {
177 	int i;
178 
179 	if ((i = ffsl(pg->freemask[0])) != 0)
180 		return (i);
181 	if ((i = ffsl(pg->freemask[1])) != 0)
182 		return (i + 32);
183 	return (0);
184 }
185 
186 #endif
187 
188 TAILQ_HEAD(nat64lsn_job_head, nat64lsn_job_item);
189 
190 #define	NAT64LSN_FLAGSMASK	(NAT64_LOG)
191 struct nat64lsn_cfg {
192 	struct named_object	no;
193 	//struct nat64_exthost	*ex;	/* Pointer to external addr array */
194 	struct nat64lsn_portgroup	**pg;	/* XXX: array of pointers */
195 	struct nat64lsn_host	**ih;	/* Host hash */
196 	uint32_t	prefix4;	/* IPv4 prefix */
197 	uint32_t	pmask4;		/* IPv4 prefix mask */
198 	uint32_t	ihsize;		/* IPv6 host hash size */
199 	uint8_t		plen4;
200 	uint8_t		plen6;
201 	uint8_t		nomatch_verdict;/* What to return to ipfw on no-match */
202 	uint8_t		nomatch_final;	/* Exit outer loop? */
203 	struct in6_addr	prefix6;	/* IPv6 prefix to embed IPv4 hosts */
204 
205 	uint32_t	ihcount;	/* Number of items in host hash */
206 	int		max_chunks;	/* Max chunks per client */
207 	int		agg_prefix_len;	/* Prefix length to count */
208 	int		agg_prefix_max;	/* Max hosts per agg prefix */
209 	uint32_t	jmaxlen;	/* Max jobqueue length */
210 	uint32_t	flags;
211 	uint16_t	min_chunk;	/* Min port group # to use */
212 	uint16_t	max_chunk;	/* Max port group # to use */
213 	uint16_t	nh_delete_delay;	/* Stale host delete delay */
214 	uint16_t	pg_delete_delay;	/* Stale portgroup del delay */
215 	uint16_t	st_syn_ttl;	/* TCP syn expire */
216 	uint16_t	st_close_ttl;	/* TCP fin expire */
217 	uint16_t	st_estab_ttl;	/* TCP established expire */
218 	uint16_t	st_udp_ttl;	/* UDP expire */
219 	uint16_t	st_icmp_ttl;	/* ICMP expire */
220 	uint32_t	protochunks[NAT_MAX_PROTO];/* Number of chunks used */
221 
222 	struct callout		periodic;
223 	struct callout		jcallout;
224 	struct ip_fw_chain	*ch;
225 	struct vnet		*vp;
226 	struct nat64lsn_job_head	jhead;
227 	int			jlen;
228 	char			name[64];	/* Nat instance name */
229 	nat64_stats_block	stats;
230 };
231 
232 struct nat64lsn_cfg *nat64lsn_init_instance(struct ip_fw_chain *ch,
233     size_t numaddr);
234 void nat64lsn_destroy_instance(struct nat64lsn_cfg *cfg);
235 void nat64lsn_start_instance(struct nat64lsn_cfg *cfg);
236 void nat64lsn_init_internal(void);
237 void nat64lsn_uninit_internal(void);
238 int ipfw_nat64lsn(struct ip_fw_chain *ch, struct ip_fw_args *args,
239     ipfw_insn *cmd, int *done);
240 
241 void
242 nat64lsn_dump_state(const struct nat64lsn_cfg *cfg,
243     const struct nat64lsn_portgroup *pg, const struct nat64lsn_state *st,
244     const char *px, int off);
245 /*
246  * Portgroup layout
247  * addr x nat_proto x port_off
248  *
249  */
250 
251 #define	_ADDR_PG_PROTO_COUNT	(65536 >> NAT64_CHUNK_SIZE_BITS)
252 #define	_ADDR_PG_COUNT		(_ADDR_PG_PROTO_COUNT * NAT_MAX_PROTO)
253 
254 #define	GET_ADDR_IDX(_cfg, _addr)	((_addr) - ((_cfg)->prefix4))
255 #define	__GET_PORTGROUP_IDX(_proto, _port)	\
256     ((_proto - 1) * _ADDR_PG_PROTO_COUNT +	\
257 	((_port) >> NAT64_CHUNK_SIZE_BITS))
258 
259 #define	_GET_PORTGROUP_IDX(_cfg, _addr, _proto, _port)	\
260     GET_ADDR_IDX(_cfg, _addr) * _ADDR_PG_COUNT +	\
261 	__GET_PORTGROUP_IDX(_proto, _port)
262 #define	GET_PORTGROUP(_cfg, _addr, _proto, _port)	\
263     ((_cfg)->pg[_GET_PORTGROUP_IDX(_cfg, _addr, _proto, _port)])
264 
265 #define	PORTGROUP_CHUNK(_nh, _idx)		\
266     ((_nh)->pg_ptr[(_idx)])
267 #define	PORTGROUP_BYSIDX(_cfg, _nh, _idx)	\
268     (PORTGROUP_CHUNK(_nh, (_idx - 1) / NAT64LSN_PGIDX_CHUNK) \
269 	[((_idx) - 1) % NAT64LSN_PGIDX_CHUNK])
270 
271 
272 /* Chained hash table */
273 #define CHT_FIND(_ph, _hsize, _PX, _x, _key) do {			\
274 	unsigned int _buck = _PX##hash(_key) & (_hsize - 1);		\
275 	_PX##lock(_ph, _buck);						\
276 	_x = _PX##first(_ph, _buck);					\
277 	for ( ; _x != NULL; _x = _PX##next(_x)) {			\
278 		if (_PX##cmp(_key, _PX##val(_x)))			\
279 			break;						\
280 	}								\
281 	if (_x == NULL)							\
282 		_PX##unlock(_ph, _buck);				\
283 } while(0)
284 
285 #define	CHT_UNLOCK_BUCK(_ph, _PX, _buck)				\
286 	_PX##unlock(_ph, _buck);
287 
288 #define	CHT_UNLOCK_KEY(_ph, _hsize, _PX, _key) do {			\
289 	unsigned int _buck = _PX##hash(_key) & (_hsize - 1);		\
290 	_PX##unlock(_ph, _buck);					\
291 } while(0)
292 
293 #define	CHT_INSERT_HEAD(_ph, _hsize, _PX, _i) do {			\
294 	unsigned int _buck = _PX##hash(_PX##val(_i)) & (_hsize - 1);	\
295 	_PX##lock(_ph, _buck);						\
296 	_PX##next(_i) = _PX##first(_ph, _buck);				\
297 	_PX##first(_ph, _buck) = _i;					\
298 	_PX##unlock(_ph, _buck);					\
299 } while(0)
300 
301 #define	CHT_REMOVE(_ph, _hsize, _PX, _x, _tmp, _key) do {		\
302 	unsigned int _buck = _PX##hash(_key) & (_hsize - 1);		\
303 	_PX##lock(_ph, _buck);						\
304 	_x = _PX##first(_ph, _buck);					\
305 	_tmp = NULL;							\
306 	for ( ; _x != NULL; _tmp = _x, _x = _PX##next(_x)) {		\
307 		if (_PX##cmp(_key, _PX##val(_x)))			\
308 			break;						\
309 	}								\
310 	if (_x != NULL) {						\
311 		if (_tmp == NULL)					\
312 			_PX##first(_ph, _buck) = _PX##next(_x);		\
313 		else							\
314 			_PX##next(_tmp) = _PX##next(_x);		\
315 	}								\
316 	_PX##unlock(_ph, _buck);					\
317 } while(0)
318 
319 #define	CHT_FOREACH_SAFE(_ph, _hsize, _PX, _x, _tmp, _cb, _arg) do {	\
320 	for (unsigned int _i = 0; _i < _hsize; _i++) {			\
321 		_PX##lock(_ph, _i);					\
322 		_x = _PX##first(_ph, _i);				\
323 		_tmp = NULL;						\
324 		for (; _x != NULL; _tmp = _x, _x = _PX##next(_x)) {	\
325 			if (_cb(_x, _arg) == 0)				\
326 				continue;				\
327 			if (_tmp == NULL)				\
328 				_PX##first(_ph, _i) = _PX##next(_x);	\
329 			else						\
330 				_tmp = _PX##next(_x);			\
331 		}							\
332 		_PX##unlock(_ph, _i);					\
333 	}								\
334 } while(0)
335 
336 #define	CHT_RESIZE(_ph, _hsize, _nph, _nhsize, _PX, _x, _y) do {	\
337 	unsigned int _buck;						\
338 	for (unsigned int _i = 0; _i < _hsize; _i++) {			\
339 		_x = _PX##first(_ph, _i);				\
340 		_y = _x;						\
341 		while (_y != NULL) {					\
342 			_buck = _PX##hash(_PX##val(_x)) & (_nhsize - 1);\
343 			_y = _PX##next(_x);				\
344 			_PX##next(_x) = _PX##first(_nph, _buck);	\
345 			_PX##first(_nph, _buck) = _x;			\
346 		}							\
347 	}								\
348 } while(0)
349 
350 #endif /* _IP_FW_NAT64LSN_H_ */
351 
352