]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netpfil/ipfw/nat64/nat64lsn.h
MFV r311899:
[FreeBSD/FreeBSD.git] / sys / netpfil / ipfw / nat64 / nat64lsn.h
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