]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netpfil/ipfw/nat64/nat64lsn.c
Merge from stable/11:
[FreeBSD/FreeBSD.git] / sys / netpfil / ipfw / nat64 / nat64lsn.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2015-2019 Yandex LLC
5  * Copyright (c) 2015 Alexander V. Chernikov <melifaro@FreeBSD.org>
6  * Copyright (c) 2016-2019 Andrey V. Elsukov <ae@FreeBSD.org>
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  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/counter.h>
36 #include <sys/errno.h>
37 #include <sys/kernel.h>
38 #include <sys/lock.h>
39 #include <sys/malloc.h>
40 #include <sys/mbuf.h>
41 #include <sys/module.h>
42 #include <sys/rmlock.h>
43 #include <sys/rwlock.h>
44 #include <sys/socket.h>
45 #include <sys/queue.h>
46 #include <sys/syslog.h>
47 #include <sys/sysctl.h>
48
49 #include <net/if.h>
50 #include <net/if_var.h>
51 #include <net/if_pflog.h>
52 #include <net/pfil.h>
53
54 #include <netinet/in.h>
55 #include <netinet/ip.h>
56 #include <netinet/ip_var.h>
57 #include <netinet/ip_fw.h>
58 #include <netinet/ip6.h>
59 #include <netinet/icmp6.h>
60 #include <netinet/ip_icmp.h>
61 #include <netinet/tcp.h>
62 #include <netinet/udp.h>
63 #include <netinet6/in6_var.h>
64 #include <netinet6/ip6_var.h>
65 #include <netinet6/ip_fw_nat64.h>
66
67 #include <netpfil/ipfw/ip_fw_private.h>
68 #include <netpfil/pf/pf.h>
69
70 #include "nat64lsn.h"
71
72 MALLOC_DEFINE(M_NAT64LSN, "NAT64LSN", "NAT64LSN");
73
74 static void nat64lsn_periodic(void *data);
75 #define PERIODIC_DELAY  4
76 static uint8_t nat64lsn_proto_map[256];
77 uint8_t nat64lsn_rproto_map[NAT_MAX_PROTO];
78
79 #define NAT64_FLAG_FIN          0x01    /* FIN was seen */
80 #define NAT64_FLAG_SYN          0x02    /* First syn in->out */
81 #define NAT64_FLAG_ESTAB        0x04    /* Packet with Ack */
82 #define NAT64_FLAGS_TCP (NAT64_FLAG_SYN|NAT64_FLAG_ESTAB|NAT64_FLAG_FIN)
83
84 #define NAT64_FLAG_RDR          0x80    /* Port redirect */
85 #define NAT64_LOOKUP(chain, cmd)        \
86         (struct nat64lsn_cfg *)SRV_OBJECT((chain), (cmd)->arg1)
87 /*
88  * Delayed job queue, used to create new hosts
89  * and new portgroups
90  */
91 enum nat64lsn_jtype {
92         JTYPE_NEWHOST = 1,
93         JTYPE_NEWPORTGROUP,
94         JTYPE_DELPORTGROUP,
95 };
96
97 struct nat64lsn_job_item {
98         TAILQ_ENTRY(nat64lsn_job_item)  next;
99         enum nat64lsn_jtype     jtype;
100         struct nat64lsn_host    *nh;
101         struct nat64lsn_portgroup       *pg;
102         void                    *spare_idx;
103         struct in6_addr         haddr;
104         uint8_t                 nat_proto;
105         uint8_t                 done;
106         int                     needs_idx;
107         int                     delcount;
108         unsigned int            fhash;  /* Flow hash */
109         uint32_t                aaddr;  /* Last used address (net) */
110         struct mbuf             *m;
111         struct ipfw_flow_id     f_id;
112         uint64_t                delmask[NAT64LSN_PGPTRNMASK];
113 };
114
115 static struct mtx jmtx;
116 #define JQUEUE_LOCK_INIT()      mtx_init(&jmtx, "qlock", NULL, MTX_DEF)
117 #define JQUEUE_LOCK_DESTROY()   mtx_destroy(&jmtx)
118 #define JQUEUE_LOCK()           mtx_lock(&jmtx)
119 #define JQUEUE_UNLOCK()         mtx_unlock(&jmtx)
120
121 static void nat64lsn_enqueue_job(struct nat64lsn_cfg *cfg,
122     struct nat64lsn_job_item *ji);
123 static void nat64lsn_enqueue_jobs(struct nat64lsn_cfg *cfg,
124     struct nat64lsn_job_head *jhead, int jlen);
125
126 static struct nat64lsn_job_item *nat64lsn_create_job(struct nat64lsn_cfg *cfg,
127     const struct ipfw_flow_id *f_id, int jtype);
128 static int nat64lsn_request_portgroup(struct nat64lsn_cfg *cfg,
129     const struct ipfw_flow_id *f_id, struct mbuf **pm, uint32_t aaddr,
130     int needs_idx);
131 static int nat64lsn_request_host(struct nat64lsn_cfg *cfg,
132     const struct ipfw_flow_id *f_id, struct mbuf **pm);
133 static int nat64lsn_translate4(struct nat64lsn_cfg *cfg,
134     const struct ipfw_flow_id *f_id, struct mbuf **pm);
135 static int nat64lsn_translate6(struct nat64lsn_cfg *cfg,
136     struct ipfw_flow_id *f_id, struct mbuf **pm);
137
138 static int alloc_portgroup(struct nat64lsn_job_item *ji);
139 static void destroy_portgroup(struct nat64lsn_portgroup *pg);
140 static void destroy_host6(struct nat64lsn_host *nh);
141 static int alloc_host6(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji);
142
143 static int attach_portgroup(struct nat64lsn_cfg *cfg,
144     struct nat64lsn_job_item *ji);
145 static int attach_host6(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji);
146
147
148 /* XXX tmp */
149 static uma_zone_t nat64lsn_host_zone;
150 static uma_zone_t nat64lsn_pg_zone;
151 static uma_zone_t nat64lsn_pgidx_zone;
152
153 static unsigned int nat64lsn_periodic_chkstates(struct nat64lsn_cfg *cfg,
154     struct nat64lsn_host *nh);
155
156 #define I6_hash(x)              (djb_hash((const unsigned char *)(x), 16))
157 #define I6_first(_ph, h)        (_ph)[h]
158 #define I6_next(x)              (x)->next
159 #define I6_val(x)               (&(x)->addr)
160 #define I6_cmp(a, b)            IN6_ARE_ADDR_EQUAL(a, b)
161 #define I6_lock(a, b)
162 #define I6_unlock(a, b)
163
164 #define I6HASH_FIND(_cfg, _res, _a) \
165         CHT_FIND(_cfg->ih, _cfg->ihsize, I6_, _res, _a)
166 #define I6HASH_INSERT(_cfg, _i) \
167         CHT_INSERT_HEAD(_cfg->ih, _cfg->ihsize, I6_, _i)
168 #define I6HASH_REMOVE(_cfg, _res, _tmp, _a)     \
169         CHT_REMOVE(_cfg->ih, _cfg->ihsize, I6_, _res, _tmp, _a)
170
171 #define I6HASH_FOREACH_SAFE(_cfg, _x, _tmp, _cb, _arg)  \
172         CHT_FOREACH_SAFE(_cfg->ih, _cfg->ihsize, I6_, _x, _tmp, _cb, _arg)
173
174 #define HASH_IN4(x)     djb_hash((const unsigned char *)(x), 8)
175
176 static unsigned
177 djb_hash(const unsigned char *h, const int len)
178 {
179         unsigned int result = 0;
180         int i;
181
182         for (i = 0; i < len; i++)
183                 result = 33 * result ^ h[i];
184
185         return (result);
186 }
187
188 /*
189 static size_t 
190 bitmask_size(size_t num, int *level)
191 {
192         size_t x;
193         int c;
194
195         for (c = 0, x = num; num > 1; num /= 64, c++)
196                 ;
197
198         return (x);
199 }
200
201 static void
202 bitmask_prepare(uint64_t *pmask, size_t bufsize, int level)
203 {
204         size_t x, z;
205
206         memset(pmask, 0xFF, bufsize);
207         for (x = 0, z = 1; level > 1; x += z, z *= 64, level--)
208                 ;
209         pmask[x] ~= 0x01;
210 }
211 */
212
213 static void
214 nat64lsn_log(struct pfloghdr *plog, struct mbuf *m, sa_family_t family,
215     uint32_t n, uint32_t sn)
216 {
217
218         memset(plog, 0, sizeof(*plog));
219         plog->length = PFLOG_REAL_HDRLEN;
220         plog->af = family;
221         plog->action = PF_NAT;
222         plog->dir = PF_IN;
223         plog->rulenr = htonl(n);
224         plog->subrulenr = htonl(sn);
225         plog->ruleset[0] = '\0';
226         strlcpy(plog->ifname, "NAT64LSN", sizeof(plog->ifname));
227         ipfw_bpf_mtap2(plog, PFLOG_HDRLEN, m);
228 }
229 /*
230  * Inspects icmp packets to see if the message contains different
231  * packet header so we need to alter @addr and @port.
232  */
233 static int
234 inspect_icmp_mbuf(struct mbuf **m, uint8_t *nat_proto, uint32_t *addr,
235     uint16_t *port)
236 {
237         struct ip *ip;
238         struct tcphdr *tcp;
239         struct udphdr *udp;
240         struct icmphdr *icmp;
241         int off;
242         uint8_t proto;
243
244         ip = mtod(*m, struct ip *); /* Outer IP header */
245         off = (ip->ip_hl << 2) + ICMP_MINLEN;
246         if ((*m)->m_len < off)
247                 *m = m_pullup(*m, off);
248         if (*m == NULL)
249                 return (ENOMEM);
250
251         ip = mtod(*m, struct ip *); /* Outer IP header */
252         icmp = L3HDR(ip, struct icmphdr *);
253         switch (icmp->icmp_type) {
254         case ICMP_ECHO:
255         case ICMP_ECHOREPLY:
256                 /* Use icmp ID as distinguisher */
257                 *port = ntohs(*((uint16_t *)(icmp + 1)));
258                 return (0);
259         case ICMP_UNREACH:
260         case ICMP_TIMXCEED:
261                 break;
262         default:
263                 return (EOPNOTSUPP);
264         }
265         /*
266          * ICMP_UNREACH and ICMP_TIMXCEED contains IP header + 64 bits
267          * of ULP header.
268          */
269         if ((*m)->m_pkthdr.len < off + sizeof(struct ip) + ICMP_MINLEN)
270                 return (EINVAL);
271         if ((*m)->m_len < off + sizeof(struct ip) + ICMP_MINLEN)
272                 *m = m_pullup(*m, off + sizeof(struct ip) + ICMP_MINLEN);
273         if (*m == NULL)
274                 return (ENOMEM);
275         ip = mtodo(*m, off); /* Inner IP header */
276         proto = ip->ip_p;
277         off += ip->ip_hl << 2; /* Skip inner IP header */
278         *addr = ntohl(ip->ip_src.s_addr);
279         if ((*m)->m_len < off + ICMP_MINLEN)
280                 *m = m_pullup(*m, off + ICMP_MINLEN);
281         if (*m == NULL)
282                 return (ENOMEM);
283         switch (proto) {
284         case IPPROTO_TCP:
285                 tcp = mtodo(*m, off);
286                 *nat_proto = NAT_PROTO_TCP;
287                 *port = ntohs(tcp->th_sport);
288                 return (0);
289         case IPPROTO_UDP:
290                 udp = mtodo(*m, off);
291                 *nat_proto = NAT_PROTO_UDP;
292                 *port = ntohs(udp->uh_sport);
293                 return (0);
294         case IPPROTO_ICMP:
295                 /*
296                  * We will translate only ICMP errors for our ICMP
297                  * echo requests.
298                  */
299                 icmp = mtodo(*m, off);
300                 if (icmp->icmp_type != ICMP_ECHO)
301                         return (EOPNOTSUPP);
302                 *port = ntohs(*((uint16_t *)(icmp + 1)));
303                 return (0);
304         };
305         return (EOPNOTSUPP);
306 }
307
308 static inline uint8_t
309 convert_tcp_flags(uint8_t flags)
310 {
311         uint8_t result;
312
313         result = flags & (TH_FIN|TH_SYN);
314         result |= (flags & TH_RST) >> 2; /* Treat RST as FIN */
315         result |= (flags & TH_ACK) >> 2; /* Treat ACK as estab */
316
317         return (result);
318 }
319
320 static NAT64NOINLINE int
321 nat64lsn_translate4(struct nat64lsn_cfg *cfg, const struct ipfw_flow_id *f_id,
322     struct mbuf **pm)
323 {
324         struct pfloghdr loghdr, *logdata;
325         struct in6_addr src6;
326         struct nat64lsn_portgroup *pg;
327         struct nat64lsn_host *nh;
328         struct nat64lsn_state *st;
329         struct ip *ip;
330         uint32_t addr;
331         uint16_t state_flags, state_ts;
332         uint16_t port, lport;
333         uint8_t nat_proto;
334         int ret;
335
336         addr = f_id->dst_ip;
337         port = f_id->dst_port;
338         if (addr < cfg->prefix4 || addr > cfg->pmask4) {
339                 NAT64STAT_INC(&cfg->base.stats, nomatch4);
340                 return (cfg->nomatch_verdict);
341         }
342
343         /* Check if protocol is supported and get its short id */
344         nat_proto = nat64lsn_proto_map[f_id->proto];
345         if (nat_proto == 0) {
346                 NAT64STAT_INC(&cfg->base.stats, noproto);
347                 return (cfg->nomatch_verdict);
348         }
349
350         /* We might need to handle icmp differently */
351         if (nat_proto == NAT_PROTO_ICMP) {
352                 ret = inspect_icmp_mbuf(pm, &nat_proto, &addr, &port);
353                 if (ret != 0) {
354                         if (ret == ENOMEM) {
355                                 NAT64STAT_INC(&cfg->base.stats, nomem);
356                                 return (IP_FW_DENY);
357                         }
358                         NAT64STAT_INC(&cfg->base.stats, noproto);
359                         return (cfg->nomatch_verdict);
360                 }
361                 /* XXX: Check addr for validity */
362                 if (addr < cfg->prefix4 || addr > cfg->pmask4) {
363                         NAT64STAT_INC(&cfg->base.stats, nomatch4);
364                         return (cfg->nomatch_verdict);
365                 }
366         }
367
368         /* Calc portgroup offset w.r.t protocol */
369         pg = GET_PORTGROUP(cfg, addr, nat_proto, port);
370
371         /* Check if this port is occupied by any portgroup */
372         if (pg == NULL) {
373                 NAT64STAT_INC(&cfg->base.stats, nomatch4);
374 #if 0
375                 DPRINTF(DP_STATE, "NOMATCH %u %d %d (%d)", addr, nat_proto, port,
376                     _GET_PORTGROUP_IDX(cfg, addr, nat_proto, port));
377 #endif
378                 return (cfg->nomatch_verdict);
379         }
380
381         /* TODO: Check flags to see if we need to do some static mapping */
382         nh = pg->host;
383
384         /* Prepare some fields we might need to update */
385         SET_AGE(state_ts);
386         ip = mtod(*pm, struct ip *);
387         if (ip->ip_p == IPPROTO_TCP)
388                 state_flags = convert_tcp_flags(
389                     L3HDR(ip, struct tcphdr *)->th_flags);
390         else
391                 state_flags = 0;
392
393         /* Lock host and get port mapping */
394         NAT64_LOCK(nh);
395
396         st = &pg->states[port & (NAT64_CHUNK_SIZE - 1)];
397         if (st->timestamp != state_ts)
398                 st->timestamp = state_ts;
399         if ((st->flags & state_flags) != state_flags)
400                 st->flags |= state_flags;
401         lport = htons(st->u.s.lport);
402
403         NAT64_UNLOCK(nh);
404
405         if (cfg->base.flags & NAT64_LOG) {
406                 logdata = &loghdr;
407                 nat64lsn_log(logdata, *pm, AF_INET, pg->idx, st->cur.off);
408         } else
409                 logdata = NULL;
410
411         src6 = cfg->base.plat_prefix;
412         nat64_embed_ip4(&src6, cfg->base.plat_plen, htonl(f_id->src_ip));
413         ret = nat64_do_handle_ip4(*pm, &src6, &nh->addr, lport,
414             &cfg->base, logdata);
415
416         if (ret == NAT64SKIP)
417                 return (cfg->nomatch_verdict);
418         if (ret == NAT64MFREE)
419                 m_freem(*pm);
420         *pm = NULL;
421
422         return (IP_FW_DENY);
423 }
424
425 void
426 nat64lsn_dump_state(const struct nat64lsn_cfg *cfg,
427    const struct nat64lsn_portgroup *pg, const struct nat64lsn_state *st,
428    const char *px, int off)
429 {
430         char s[INET6_ADDRSTRLEN], a[INET_ADDRSTRLEN], d[INET_ADDRSTRLEN];
431
432         if ((V_nat64_debug & DP_STATE) == 0)
433                 return;
434         inet_ntop(AF_INET6, &pg->host->addr, s, sizeof(s));
435         inet_ntop(AF_INET, &pg->aaddr, a, sizeof(a));
436         inet_ntop(AF_INET, &st->u.s.faddr, d, sizeof(d));
437
438         DPRINTF(DP_STATE, "%s: PG %d ST [%p|%d]: %s:%d/%d <%s:%d> "
439             "%s:%d AGE %d", px, pg->idx, st, off,
440             s, st->u.s.lport, pg->nat_proto, a, pg->aport + off,
441             d, st->u.s.fport, GET_AGE(st->timestamp));
442 }
443
444 /*
445  * Check if particular TCP state is stale and should be deleted.
446  * Return 1 if true, 0 otherwise.
447  */
448 static int
449 nat64lsn_periodic_check_tcp(const struct nat64lsn_cfg *cfg,
450     const struct nat64lsn_state *st, int age)
451 {
452         int ttl;
453
454         if (st->flags & NAT64_FLAG_FIN)
455                 ttl = cfg->st_close_ttl;
456         else if (st->flags & NAT64_FLAG_ESTAB)
457                 ttl = cfg->st_estab_ttl;
458         else if (st->flags & NAT64_FLAG_SYN)
459                 ttl = cfg->st_syn_ttl;
460         else
461                 ttl = cfg->st_syn_ttl;
462
463         if (age > ttl)
464                 return (1);
465         return (0);
466 }
467
468 /*
469  * Check if nat state @st is stale and should be deleted.
470  * Return 1 if true, 0 otherwise.
471  */
472 static NAT64NOINLINE int
473 nat64lsn_periodic_chkstate(const struct nat64lsn_cfg *cfg,
474     const struct nat64lsn_portgroup *pg, const struct nat64lsn_state *st)
475 {
476         int age, delete;
477
478         age = GET_AGE(st->timestamp);
479         delete = 0;
480
481         /* Skip immutable records */
482         if (st->flags & NAT64_FLAG_RDR)
483                 return (0);
484
485         switch (pg->nat_proto) {
486                 case NAT_PROTO_TCP:
487                         delete = nat64lsn_periodic_check_tcp(cfg, st, age);
488                         break;
489                 case NAT_PROTO_UDP:
490                         if (age > cfg->st_udp_ttl)
491                                 delete = 1;
492                         break;
493                 case NAT_PROTO_ICMP:
494                         if (age > cfg->st_icmp_ttl)
495                                 delete = 1;
496                         break;
497         }
498
499         return (delete);
500 }
501
502
503 /*
504  * The following structures and functions
505  * are used to perform SLIST_FOREACH_SAFE()
506  * analog for states identified by struct st_ptr.
507  */
508
509 struct st_idx {
510         struct nat64lsn_portgroup *pg;
511         struct nat64lsn_state *st;
512         struct st_ptr sidx_next;
513 };
514
515 static struct st_idx *
516 st_first(const struct nat64lsn_cfg *cfg, const struct nat64lsn_host *nh,
517     struct st_ptr *sidx, struct st_idx *si)
518 {
519         struct nat64lsn_portgroup *pg;
520         struct nat64lsn_state *st;
521
522         if (sidx->idx == 0) {
523                 memset(si, 0, sizeof(*si));
524                 return (si);
525         }
526
527         pg = PORTGROUP_BYSIDX(cfg, nh, sidx->idx);
528         st = &pg->states[sidx->off];
529
530         si->pg = pg;
531         si->st = st;
532         si->sidx_next = st->next;
533
534         return (si);
535 }
536
537 static struct st_idx *
538 st_next(const struct nat64lsn_cfg *cfg, const struct nat64lsn_host *nh,
539     struct st_idx *si)
540 {
541         struct st_ptr sidx;
542         struct nat64lsn_portgroup *pg;
543         struct nat64lsn_state *st;
544
545         sidx = si->sidx_next;
546         if (sidx.idx == 0) {
547                 memset(si, 0, sizeof(*si));
548                 si->st = NULL;
549                 si->pg = NULL;
550                 return (si);
551         }
552
553         pg = PORTGROUP_BYSIDX(cfg, nh, sidx.idx);
554         st = &pg->states[sidx.off];
555
556         si->pg = pg;
557         si->st = st;
558         si->sidx_next = st->next;
559
560         return (si);
561 }
562
563 static struct st_idx *
564 st_save_cond(struct st_idx *si_dst, struct st_idx *si)
565 {
566         if (si->st != NULL)
567                 *si_dst = *si;
568
569         return (si_dst);
570 }
571
572 unsigned int
573 nat64lsn_periodic_chkstates(struct nat64lsn_cfg *cfg, struct nat64lsn_host *nh)
574 {
575         struct st_idx si, si_prev;
576         int i;
577         unsigned int delcount;
578
579         delcount = 0;
580         for (i = 0; i < nh->hsize; i++) {
581                 memset(&si_prev, 0, sizeof(si_prev));
582                 for (st_first(cfg, nh, &nh->phash[i], &si);
583                     si.st != NULL;
584                     st_save_cond(&si_prev, &si), st_next(cfg, nh, &si)) {
585                         if (nat64lsn_periodic_chkstate(cfg, si.pg, si.st) == 0)
586                                 continue;
587                         nat64lsn_dump_state(cfg, si.pg, si.st, "DELETE STATE",
588                             si.st->cur.off);
589                         /* Unlink from hash */
590                         if (si_prev.st != NULL)
591                                 si_prev.st->next = si.st->next;
592                         else
593                                 nh->phash[i] = si.st->next;
594                         /* Delete state and free its data */
595                         PG_MARK_FREE_IDX(si.pg, si.st->cur.off);
596                         memset(si.st, 0, sizeof(struct nat64lsn_state));
597                         si.st = NULL;
598                         delcount++;
599
600                         /* Update portgroup timestamp */
601                         SET_AGE(si.pg->timestamp);
602                 }
603         }
604         NAT64STAT_ADD(&cfg->base.stats, sdeleted, delcount);
605         return (delcount);
606 }
607
608 /*
609  * Checks if portgroup is not used and can be deleted,
610  * Returns 1 if stale, 0 otherwise
611  */
612 static int
613 stale_pg(const struct nat64lsn_cfg *cfg, const struct nat64lsn_portgroup *pg)
614 {
615
616         if (!PG_IS_EMPTY(pg))
617                 return (0);
618         if (GET_AGE(pg->timestamp) < cfg->pg_delete_delay)
619                 return (0);
620         return (1);
621 }
622
623 /*
624  * Checks if host record is not used and can be deleted,
625  * Returns 1 if stale, 0 otherwise
626  */
627 static int
628 stale_nh(const struct nat64lsn_cfg *cfg, const struct nat64lsn_host *nh)
629 {
630
631         if (nh->pg_used != 0)
632                 return (0);
633         if (GET_AGE(nh->timestamp) < cfg->nh_delete_delay)
634                 return (0);
635         return (1);
636 }
637
638 struct nat64lsn_periodic_data {
639         struct nat64lsn_cfg *cfg;
640         struct nat64lsn_job_head jhead;
641         int jlen;
642 };
643
644 static NAT64NOINLINE int
645 nat64lsn_periodic_chkhost(struct nat64lsn_host *nh,
646     struct nat64lsn_periodic_data *d)
647 {
648         struct nat64lsn_portgroup *pg;
649         struct nat64lsn_job_item *ji;
650         uint64_t delmask[NAT64LSN_PGPTRNMASK];
651         int delcount, i;
652
653         delcount = 0;
654         memset(delmask, 0, sizeof(delmask));
655
656         if (V_nat64_debug & DP_JQUEUE) {
657                 char a[INET6_ADDRSTRLEN];
658
659                 inet_ntop(AF_INET6, &nh->addr, a, sizeof(a));
660                 DPRINTF(DP_JQUEUE, "Checking %s host %s on cpu %d",
661                     stale_nh(d->cfg, nh) ? "stale" : "non-stale", a, curcpu);
662         }
663         if (!stale_nh(d->cfg, nh)) {
664                 /* Non-stale host. Inspect internals */
665                 NAT64_LOCK(nh);
666
667                 /* Stage 1: Check&expire states */
668                 if (nat64lsn_periodic_chkstates(d->cfg, nh) != 0)
669                         SET_AGE(nh->timestamp);
670
671                 /* Stage 2: Check if we need to expire */
672                 for (i = 0; i < nh->pg_used; i++) {
673                         pg = PORTGROUP_BYSIDX(d->cfg, nh, i + 1);
674                         if (pg == NULL)
675                                 continue;
676
677                         /* Check if we can delete portgroup */
678                         if (stale_pg(d->cfg, pg) == 0)
679                                 continue;
680
681                         DPRINTF(DP_JQUEUE, "Check PG %d", i);
682                         delmask[i / 64] |= ((uint64_t)1 << (i % 64));
683                         delcount++;
684                 }
685
686                 NAT64_UNLOCK(nh);
687                 if (delcount == 0)
688                         return (0);
689         }
690
691         DPRINTF(DP_JQUEUE, "Queueing %d portgroups for deleting", delcount);
692         /* We have something to delete - add it to queue */
693         ji = nat64lsn_create_job(d->cfg, NULL, JTYPE_DELPORTGROUP);
694         if (ji == NULL)
695                 return (0);
696
697         ji->haddr = nh->addr;
698         ji->delcount = delcount;
699         memcpy(ji->delmask, delmask, sizeof(ji->delmask));
700
701         TAILQ_INSERT_TAIL(&d->jhead, ji, next);
702         d->jlen++;
703         return (0);
704 }
705
706 /*
707  * This procedure is used to perform various maintance
708  * on dynamic hash list. Currently it is called every second.
709  */
710 static void
711 nat64lsn_periodic(void *data)
712 {
713         struct ip_fw_chain *ch;
714         IPFW_RLOCK_TRACKER;
715         struct nat64lsn_cfg *cfg;
716         struct nat64lsn_periodic_data d;
717         struct nat64lsn_host *nh, *tmp;
718
719         cfg = (struct nat64lsn_cfg *) data;
720         ch = cfg->ch;
721         CURVNET_SET(cfg->vp);
722
723         memset(&d, 0, sizeof(d));
724         d.cfg = cfg;
725         TAILQ_INIT(&d.jhead);
726
727         IPFW_RLOCK(ch);
728
729         /* Stage 1: foreach host, check all its portgroups */
730         I6HASH_FOREACH_SAFE(cfg, nh, tmp, nat64lsn_periodic_chkhost, &d);
731
732         /* Enqueue everything we have requested */
733         nat64lsn_enqueue_jobs(cfg, &d.jhead, d.jlen);
734
735         callout_schedule(&cfg->periodic, hz * PERIODIC_DELAY);
736
737         IPFW_RUNLOCK(ch);
738
739         CURVNET_RESTORE();
740 }
741
742 static NAT64NOINLINE void
743 reinject_mbuf(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
744 {
745
746         if (ji->m == NULL)
747                 return;
748
749         /* Request has failed or packet type is wrong */
750         if (ji->f_id.addr_type != 6 || ji->done == 0) {
751                 m_freem(ji->m);
752                 ji->m = NULL;
753                 NAT64STAT_INC(&cfg->base.stats, dropped);
754                 DPRINTF(DP_DROPS, "mbuf dropped: type %d, done %d",
755                     ji->jtype, ji->done);
756                 return;
757         }
758
759         /*
760          * XXX: Limit recursion level
761          */
762
763         NAT64STAT_INC(&cfg->base.stats, jreinjected);
764         DPRINTF(DP_JQUEUE, "Reinject mbuf");
765         nat64lsn_translate6(cfg, &ji->f_id, &ji->m);
766 }
767
768 static void
769 destroy_portgroup(struct nat64lsn_portgroup *pg)
770 {
771
772         DPRINTF(DP_OBJ, "DESTROY PORTGROUP %d %p", pg->idx, pg);
773         uma_zfree(nat64lsn_pg_zone, pg);
774 }
775
776 static NAT64NOINLINE int
777 alloc_portgroup(struct nat64lsn_job_item *ji)
778 {
779         struct nat64lsn_portgroup *pg;
780
781         pg = uma_zalloc(nat64lsn_pg_zone, M_NOWAIT);
782         if (pg == NULL)
783                 return (1);
784
785         if (ji->needs_idx != 0) {
786                 ji->spare_idx = uma_zalloc(nat64lsn_pgidx_zone, M_NOWAIT);
787                 /* Failed alloc isn't always fatal, so don't check */
788         }
789         memset(&pg->freemask, 0xFF, sizeof(pg->freemask));
790         pg->nat_proto = ji->nat_proto;
791         ji->pg = pg;
792         return (0);
793
794 }
795
796 static void
797 destroy_host6(struct nat64lsn_host *nh)
798 {
799         char a[INET6_ADDRSTRLEN];
800         int i;
801
802         inet_ntop(AF_INET6, &nh->addr, a, sizeof(a));
803         DPRINTF(DP_OBJ, "DESTROY HOST %s %p (pg used %d)", a, nh,
804             nh->pg_used);
805         NAT64_LOCK_DESTROY(nh);
806         for (i = 0; i < nh->pg_allocated / NAT64LSN_PGIDX_CHUNK; i++)
807                 uma_zfree(nat64lsn_pgidx_zone, PORTGROUP_CHUNK(nh, i));
808         uma_zfree(nat64lsn_host_zone, nh);
809 }
810
811 static NAT64NOINLINE int
812 alloc_host6(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
813 {
814         struct nat64lsn_host *nh;
815         char a[INET6_ADDRSTRLEN];
816
817         nh = uma_zalloc(nat64lsn_host_zone, M_NOWAIT);
818         if (nh == NULL)
819                 return (1);
820         PORTGROUP_CHUNK(nh, 0) = uma_zalloc(nat64lsn_pgidx_zone, M_NOWAIT);
821         if (PORTGROUP_CHUNK(nh, 0) == NULL) {
822                 uma_zfree(nat64lsn_host_zone, nh);
823                 return (2);
824         }
825         if (alloc_portgroup(ji) != 0) {
826                 NAT64STAT_INC(&cfg->base.stats, jportfails);
827                 uma_zfree(nat64lsn_pgidx_zone, PORTGROUP_CHUNK(nh, 0));
828                 uma_zfree(nat64lsn_host_zone, nh);
829                 return (3);
830         }
831
832         NAT64_LOCK_INIT(nh);
833         nh->addr = ji->haddr;
834         nh->hsize = NAT64LSN_HSIZE; /* XXX: hardcoded size */
835         nh->pg_allocated = NAT64LSN_PGIDX_CHUNK;
836         nh->pg_used = 0;
837         ji->nh = nh;
838
839         inet_ntop(AF_INET6, &nh->addr, a, sizeof(a));
840         DPRINTF(DP_OBJ, "ALLOC HOST %s %p", a, ji->nh);
841         return (0);
842 }
843
844 /*
845  * Finds free @pg index inside @nh
846  */
847 static NAT64NOINLINE int
848 find_nh_pg_idx(struct nat64lsn_cfg *cfg, struct nat64lsn_host *nh, int *idx)
849 {
850         int i;
851
852         for (i = 0; i < nh->pg_allocated; i++) {
853                 if (PORTGROUP_BYSIDX(cfg, nh, i + 1) == NULL) {
854                         *idx = i;
855                         return (0);
856                 }
857         }
858         return (1);
859 }
860
861 static NAT64NOINLINE int
862 attach_host6(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
863 {
864         char a[INET6_ADDRSTRLEN];
865         struct nat64lsn_host *nh;
866
867         I6HASH_FIND(cfg, nh, &ji->haddr);
868         if (nh == NULL) {
869                 /* Add new host to list */
870                 nh = ji->nh;
871                 I6HASH_INSERT(cfg, nh);
872                 cfg->ihcount++;
873                 ji->nh = NULL;
874
875                 inet_ntop(AF_INET6, &nh->addr, a, sizeof(a));
876                 DPRINTF(DP_OBJ, "ATTACH HOST %s %p", a, nh);
877                 /*
878                  * Try to add portgroup.
879                  * Note it will automatically set
880                  * 'done' on ji if successful.
881                  */
882                 if (attach_portgroup(cfg, ji) != 0) {
883                         DPRINTF(DP_DROPS, "%s %p failed to attach PG",
884                             a, nh);
885                         NAT64STAT_INC(&cfg->base.stats, jportfails);
886                         return (1);
887                 }
888                 return (0);
889         }
890
891         /*
892          * nh isn't NULL. This probably means we had several simultaneous
893          * host requests. The previous one request has already attached
894          * this host. Requeue attached mbuf and mark job as done, but
895          * leave nh and pg pointers not changed, so nat64lsn_do_request()
896          * will release all allocated resources.
897          */
898         inet_ntop(AF_INET6, &nh->addr, a, sizeof(a));
899         DPRINTF(DP_OBJ, "%s %p is already attached as %p",
900             a, ji->nh, nh);
901         ji->done = 1;
902         return (0);
903 }
904
905 static NAT64NOINLINE int
906 find_pg_place_addr(const struct nat64lsn_cfg *cfg, int addr_off,
907     int nat_proto, uint16_t *aport, int *ppg_idx)
908 {
909         int j, pg_idx;
910
911         pg_idx = addr_off * _ADDR_PG_COUNT +
912             (nat_proto - 1) * _ADDR_PG_PROTO_COUNT;
913
914         for (j = NAT64_MIN_CHUNK; j < _ADDR_PG_PROTO_COUNT; j++) {
915                 if (cfg->pg[pg_idx + j] != NULL)
916                         continue;
917
918                 *aport = j * NAT64_CHUNK_SIZE;
919                 *ppg_idx = pg_idx + j;
920                 return (1);
921         }
922
923         return (0);
924 }
925
926 /*
927  * XXX: This function needs to be rewritten to
928  * use free bitmask for faster pg finding,
929  * additionally, it should take into consideration
930  * a) randomization and
931  * b) previous addresses allocated to given nat instance
932  *
933  */
934 static NAT64NOINLINE int
935 find_portgroup_place(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji,
936     uint32_t *aaddr, uint16_t *aport, int *ppg_idx)
937 {
938         int i, nat_proto;
939
940         /*
941          * XXX: Use bitmask index to be able to find/check if IP address
942          * has some spare pg's
943          */
944         nat_proto = ji->nat_proto;
945
946         /* First, try to use same address */
947         if (ji->aaddr != 0) {
948                 i = ntohl(ji->aaddr) - cfg->prefix4;
949                 if (find_pg_place_addr(cfg, i, nat_proto, aport,
950                     ppg_idx) != 0){
951                         /* Found! */
952                         *aaddr = htonl(cfg->prefix4 + i);
953                         return (0);
954                 }
955         }
956
957         /* Next, try to use random address based on flow hash */
958         i = ji->fhash % (1 << (32 - cfg->plen4));
959         if (find_pg_place_addr(cfg, i, nat_proto, aport, ppg_idx) != 0) {
960                 /* Found! */
961                 *aaddr = htonl(cfg->prefix4 + i);
962                 return (0);
963         }
964
965
966         /* Last one: simply find ANY available */
967         for (i = 0; i < (1 << (32 - cfg->plen4)); i++) {
968                 if (find_pg_place_addr(cfg, i, nat_proto, aport,
969                     ppg_idx) != 0){
970                         /* Found! */
971                         *aaddr = htonl(cfg->prefix4 + i);
972                         return (0);
973                 }
974         }
975
976         return (1);
977 }
978
979 static NAT64NOINLINE int
980 attach_portgroup(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
981 {
982         char a[INET6_ADDRSTRLEN];
983         struct nat64lsn_portgroup *pg;
984         struct nat64lsn_host *nh;
985         uint32_t aaddr;
986         uint16_t aport;
987         int nh_pg_idx, pg_idx;
988
989         pg = ji->pg;
990
991         /*
992          * Find source host and bind: we can't rely on
993          * pg->host
994          */
995         I6HASH_FIND(cfg, nh, &ji->haddr);
996         if (nh == NULL)
997                 return (1);
998
999         /* Find spare port chunk */
1000         if (find_portgroup_place(cfg, ji, &aaddr, &aport, &pg_idx) != 0) {
1001                 inet_ntop(AF_INET6, &nh->addr, a, sizeof(a));
1002                 DPRINTF(DP_OBJ | DP_DROPS, "empty PG not found for %s", a);
1003                 return (2);
1004         }
1005
1006         /* Expand PG indexes if needed */
1007         if (nh->pg_allocated < cfg->max_chunks && ji->spare_idx != NULL) {
1008                 PORTGROUP_CHUNK(nh, nh->pg_allocated / NAT64LSN_PGIDX_CHUNK) =
1009                     ji->spare_idx;
1010                 nh->pg_allocated += NAT64LSN_PGIDX_CHUNK;
1011                 ji->spare_idx = NULL;
1012         }
1013
1014         /* Find empty index to store PG in the @nh */
1015         if (find_nh_pg_idx(cfg, nh, &nh_pg_idx) != 0) {
1016                 inet_ntop(AF_INET6, &nh->addr, a, sizeof(a));
1017                 DPRINTF(DP_OBJ | DP_DROPS, "free PG index not found for %s",
1018                     a);
1019                 return (3);
1020         }
1021
1022         cfg->pg[pg_idx] = pg;
1023         cfg->protochunks[pg->nat_proto]++;
1024         NAT64STAT_INC(&cfg->base.stats, spgcreated);
1025
1026         pg->aaddr = aaddr;
1027         pg->aport = aport;
1028         pg->host = nh;
1029         pg->idx = pg_idx;
1030         SET_AGE(pg->timestamp);
1031
1032         PORTGROUP_BYSIDX(cfg, nh, nh_pg_idx + 1) = pg;
1033         if (nh->pg_used == nh_pg_idx)
1034                 nh->pg_used++;
1035         SET_AGE(nh->timestamp);
1036
1037         ji->pg = NULL;
1038         ji->done = 1;
1039
1040         return (0);
1041 }
1042
1043 static NAT64NOINLINE void
1044 consider_del_portgroup(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
1045 {
1046         struct nat64lsn_host *nh, *nh_tmp;
1047         struct nat64lsn_portgroup *pg, *pg_list[256];
1048         int i, pg_lidx, idx;
1049
1050         /* Find source host */
1051         I6HASH_FIND(cfg, nh, &ji->haddr);
1052         if (nh == NULL || nh->pg_used == 0)
1053                 return;
1054
1055         memset(pg_list, 0, sizeof(pg_list));
1056         pg_lidx = 0;
1057
1058         NAT64_LOCK(nh);
1059
1060         for (i = nh->pg_used - 1; i >= 0; i--) {
1061                 if ((ji->delmask[i / 64] & ((uint64_t)1 << (i % 64))) == 0)
1062                         continue;
1063                 pg = PORTGROUP_BYSIDX(cfg, nh, i + 1);
1064
1065                 /* Check that PG isn't busy. */
1066                 if (stale_pg(cfg, pg) == 0)
1067                         continue;
1068
1069                 /* DO delete */
1070                 pg_list[pg_lidx++] = pg;
1071                 PORTGROUP_BYSIDX(cfg, nh, i + 1) = NULL;
1072
1073                 idx = _GET_PORTGROUP_IDX(cfg, ntohl(pg->aaddr), pg->nat_proto,
1074                     pg->aport);
1075                 KASSERT(cfg->pg[idx] == pg, ("Non matched pg"));
1076                 cfg->pg[idx] = NULL;
1077                 cfg->protochunks[pg->nat_proto]--;
1078                 NAT64STAT_INC(&cfg->base.stats, spgdeleted);
1079
1080                 /* Decrease pg_used */
1081                 while (nh->pg_used > 0 &&
1082                     PORTGROUP_BYSIDX(cfg, nh, nh->pg_used) == NULL)
1083                         nh->pg_used--;
1084
1085                 /* Check if on-stack buffer has ended */
1086                 if (pg_lidx == nitems(pg_list))
1087                         break;
1088         }
1089
1090         NAT64_UNLOCK(nh);
1091
1092         if (stale_nh(cfg, nh)) {
1093                 I6HASH_REMOVE(cfg, nh, nh_tmp, &ji->haddr);
1094                 KASSERT(nh != NULL, ("Unable to find address"));
1095                 cfg->ihcount--;
1096                 ji->nh = nh;
1097                 I6HASH_FIND(cfg, nh, &ji->haddr);
1098                 KASSERT(nh == NULL, ("Failed to delete address"));
1099         }
1100
1101         /* TODO: Delay freeing portgroups */
1102         while (pg_lidx > 0) {
1103                 pg_lidx--;
1104                 NAT64STAT_INC(&cfg->base.stats, spgdeleted);
1105                 destroy_portgroup(pg_list[pg_lidx]);
1106         }
1107 }
1108
1109 /*
1110  * Main request handler.
1111  * Responsible for handling jqueue, e.g.
1112  * creating new hosts, addind/deleting portgroups.
1113  */
1114 static NAT64NOINLINE void
1115 nat64lsn_do_request(void *data) 
1116 {
1117         IPFW_RLOCK_TRACKER;
1118         struct nat64lsn_job_head jhead;
1119         struct nat64lsn_job_item *ji;
1120         int jcount, nhsize;
1121         struct nat64lsn_cfg *cfg = (struct nat64lsn_cfg *) data;
1122         struct ip_fw_chain *ch;
1123         int delcount;
1124
1125         CURVNET_SET(cfg->vp);
1126
1127         TAILQ_INIT(&jhead);
1128
1129         /* XXX: We're running unlocked here */
1130
1131         ch = cfg->ch;
1132         delcount = 0;
1133         IPFW_RLOCK(ch);
1134
1135         /* Grab queue */
1136         JQUEUE_LOCK();
1137         TAILQ_SWAP(&jhead, &cfg->jhead, nat64lsn_job_item, next);
1138         jcount = cfg->jlen;
1139         cfg->jlen = 0;
1140         JQUEUE_UNLOCK();
1141
1142         /* check if we need to resize hash */
1143         nhsize = 0;
1144         if (cfg->ihcount > cfg->ihsize && cfg->ihsize < 65536) {
1145                 nhsize = cfg->ihsize;
1146                 for ( ; cfg->ihcount > nhsize && nhsize < 65536; nhsize *= 2)
1147                         ;
1148         } else if (cfg->ihcount < cfg->ihsize * 4) {
1149                 nhsize = cfg->ihsize;
1150                 for ( ; cfg->ihcount < nhsize * 4 && nhsize > 32; nhsize /= 2)
1151                         ;
1152         }
1153
1154         IPFW_RUNLOCK(ch);
1155
1156         if (TAILQ_EMPTY(&jhead)) {
1157                 CURVNET_RESTORE();
1158                 return;
1159         }
1160
1161         NAT64STAT_INC(&cfg->base.stats, jcalls);
1162         DPRINTF(DP_JQUEUE, "count=%d", jcount);
1163
1164         /*
1165          * TODO:
1166          * What we should do here is to build a hash
1167          * to ensure we don't have lots of duplicate requests.
1168          * Skip this for now.
1169          *
1170          * TODO: Limit per-call number of items
1171          */
1172
1173         /* Pre-allocate everything for entire chain */
1174         TAILQ_FOREACH(ji, &jhead,  next) {
1175                 switch (ji->jtype) {
1176                         case JTYPE_NEWHOST:
1177                                 if (alloc_host6(cfg, ji) != 0)
1178                                         NAT64STAT_INC(&cfg->base.stats,
1179                                             jhostfails);
1180                                 break;
1181                         case JTYPE_NEWPORTGROUP:
1182                                 if (alloc_portgroup(ji) != 0)
1183                                         NAT64STAT_INC(&cfg->base.stats,
1184                                             jportfails);
1185                                 break;
1186                         case JTYPE_DELPORTGROUP:
1187                                 delcount += ji->delcount;
1188                                 break;
1189                         default:
1190                                 break;
1191                 }
1192         }
1193
1194         /*
1195          * TODO: Alloc hew hash
1196          */
1197         nhsize = 0;
1198         if (nhsize > 0) {
1199                 /* XXX: */
1200         }
1201
1202         /* Apply all changes in batch */
1203         IPFW_UH_WLOCK(ch);
1204         IPFW_WLOCK(ch);
1205
1206         TAILQ_FOREACH(ji, &jhead,  next) {
1207                 switch (ji->jtype) {
1208                         case JTYPE_NEWHOST:
1209                                 if (ji->nh != NULL)
1210                                         attach_host6(cfg, ji);
1211                                 break;
1212                         case JTYPE_NEWPORTGROUP:
1213                                 if (ji->pg != NULL &&
1214                                     attach_portgroup(cfg, ji) != 0)
1215                                         NAT64STAT_INC(&cfg->base.stats,
1216                                             jportfails);
1217                                 break;
1218                         case JTYPE_DELPORTGROUP:
1219                                 consider_del_portgroup(cfg, ji);
1220                                 break;
1221                 }
1222         }
1223
1224         if (nhsize > 0) {
1225                 /* XXX: Move everything to new hash */
1226         }
1227
1228         IPFW_WUNLOCK(ch);
1229         IPFW_UH_WUNLOCK(ch);
1230
1231         /* Flush unused entries */
1232         while (!TAILQ_EMPTY(&jhead)) {
1233                 ji = TAILQ_FIRST(&jhead);
1234                 TAILQ_REMOVE(&jhead, ji, next);
1235                 if (ji->nh != NULL)
1236                         destroy_host6(ji->nh);
1237                 if (ji->pg != NULL)
1238                         destroy_portgroup(ji->pg);
1239                 if (ji->m != NULL)
1240                         reinject_mbuf(cfg, ji);
1241                 if (ji->spare_idx != NULL)
1242                         uma_zfree(nat64lsn_pgidx_zone, ji->spare_idx);
1243                 free(ji, M_IPFW);
1244         }
1245         CURVNET_RESTORE();
1246 }
1247
1248 static NAT64NOINLINE struct nat64lsn_job_item *
1249 nat64lsn_create_job(struct nat64lsn_cfg *cfg, const struct ipfw_flow_id *f_id,
1250     int jtype)
1251 {
1252         struct nat64lsn_job_item *ji;
1253         struct in6_addr haddr;
1254         uint8_t nat_proto;
1255
1256         /*
1257          * Do not try to lock possibly contested mutex if we're near the limit.
1258          * Drop packet instead.
1259          */
1260         if (cfg->jlen >= cfg->jmaxlen) {
1261                 NAT64STAT_INC(&cfg->base.stats, jmaxlen);
1262                 return (NULL);
1263         }
1264
1265         memset(&haddr, 0, sizeof(haddr));
1266         nat_proto = 0;
1267         if (f_id != NULL) {
1268                 haddr = f_id->src_ip6;
1269                 nat_proto = nat64lsn_proto_map[f_id->proto];
1270
1271                 DPRINTF(DP_JQUEUE, "REQUEST pg nat_proto %d on proto %d",
1272                     nat_proto, f_id->proto);
1273
1274                 if (nat_proto == 0)
1275                         return (NULL);
1276         }
1277
1278         ji = malloc(sizeof(struct nat64lsn_job_item), M_IPFW,
1279             M_NOWAIT | M_ZERO);
1280
1281         if (ji == NULL) {
1282                 NAT64STAT_INC(&cfg->base.stats, jnomem);
1283                 return (NULL);
1284         }
1285
1286         ji->jtype = jtype;
1287
1288         if (f_id != NULL) {
1289                 ji->f_id = *f_id;
1290                 ji->haddr = haddr;
1291                 ji->nat_proto = nat_proto;
1292         }
1293
1294         return (ji);
1295 }
1296
1297 static NAT64NOINLINE void
1298 nat64lsn_enqueue_job(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
1299 {
1300
1301         if (ji == NULL)
1302                 return;
1303
1304         JQUEUE_LOCK();
1305         TAILQ_INSERT_TAIL(&cfg->jhead, ji, next);
1306         cfg->jlen++;
1307         NAT64STAT_INC(&cfg->base.stats, jrequests);
1308
1309         if (callout_pending(&cfg->jcallout) == 0)
1310                 callout_reset(&cfg->jcallout, 1, nat64lsn_do_request, cfg);
1311         JQUEUE_UNLOCK();
1312 }
1313
1314 static NAT64NOINLINE void
1315 nat64lsn_enqueue_jobs(struct nat64lsn_cfg *cfg,
1316     struct nat64lsn_job_head *jhead, int jlen)
1317 {
1318
1319         if (TAILQ_EMPTY(jhead))
1320                 return;
1321
1322         /* Attach current queue to execution one */
1323         JQUEUE_LOCK();
1324         TAILQ_CONCAT(&cfg->jhead, jhead, next);
1325         cfg->jlen += jlen;
1326         NAT64STAT_ADD(&cfg->base.stats, jrequests, jlen);
1327
1328         if (callout_pending(&cfg->jcallout) == 0)
1329                 callout_reset(&cfg->jcallout, 1, nat64lsn_do_request, cfg);
1330         JQUEUE_UNLOCK();
1331 }
1332
1333 static unsigned int
1334 flow6_hash(const struct ipfw_flow_id *f_id)
1335 {
1336         unsigned char hbuf[36];
1337
1338         memcpy(hbuf, &f_id->dst_ip6, 16);
1339         memcpy(&hbuf[16], &f_id->src_ip6, 16);
1340         memcpy(&hbuf[32], &f_id->dst_port, 2);
1341         memcpy(&hbuf[32], &f_id->src_port, 2);
1342
1343         return (djb_hash(hbuf, sizeof(hbuf)));
1344 }
1345
1346 static NAT64NOINLINE int
1347 nat64lsn_request_host(struct nat64lsn_cfg *cfg,
1348     const struct ipfw_flow_id *f_id, struct mbuf **pm)
1349 {
1350         struct nat64lsn_job_item *ji;
1351         struct mbuf *m;
1352
1353         m = *pm;
1354         *pm = NULL;
1355
1356         ji = nat64lsn_create_job(cfg, f_id, JTYPE_NEWHOST);
1357         if (ji == NULL) {
1358                 m_freem(m);
1359                 NAT64STAT_INC(&cfg->base.stats, dropped);
1360                 DPRINTF(DP_DROPS, "failed to create job");
1361         } else {
1362                 ji->m = m;
1363                 /* Provide pseudo-random value based on flow */
1364                 ji->fhash = flow6_hash(f_id);
1365                 nat64lsn_enqueue_job(cfg, ji);
1366                 NAT64STAT_INC(&cfg->base.stats, jhostsreq);
1367         }
1368
1369         return (IP_FW_DENY);
1370 }
1371
1372 static NAT64NOINLINE int
1373 nat64lsn_request_portgroup(struct nat64lsn_cfg *cfg,
1374     const struct ipfw_flow_id *f_id, struct mbuf **pm, uint32_t aaddr,
1375     int needs_idx)
1376 {
1377         struct nat64lsn_job_item *ji;
1378         struct mbuf *m;
1379
1380         m = *pm;
1381         *pm = NULL;
1382
1383         ji = nat64lsn_create_job(cfg, f_id, JTYPE_NEWPORTGROUP);
1384         if (ji == NULL) {
1385                 m_freem(m);
1386                 NAT64STAT_INC(&cfg->base.stats, dropped);
1387                 DPRINTF(DP_DROPS, "failed to create job");
1388         } else {
1389                 ji->m = m;
1390                 /* Provide pseudo-random value based on flow */
1391                 ji->fhash = flow6_hash(f_id);
1392                 ji->aaddr = aaddr;
1393                 ji->needs_idx = needs_idx;
1394                 nat64lsn_enqueue_job(cfg, ji);
1395                 NAT64STAT_INC(&cfg->base.stats, jportreq);
1396         }
1397
1398         return (IP_FW_DENY);
1399 }
1400
1401 static NAT64NOINLINE struct nat64lsn_state * 
1402 nat64lsn_create_state(struct nat64lsn_cfg *cfg, struct nat64lsn_host *nh,
1403     int nat_proto, struct nat64lsn_state *kst, uint32_t *aaddr)
1404 {
1405         struct nat64lsn_portgroup *pg;
1406         struct nat64lsn_state *st;
1407         int i, hval, off;
1408
1409         /* XXX: create additional bitmask for selecting proper portgroup */
1410         for (i = 0; i < nh->pg_used; i++) {
1411                 pg = PORTGROUP_BYSIDX(cfg, nh, i + 1);
1412                 if (pg == NULL)
1413                         continue;
1414                 if (*aaddr == 0)
1415                         *aaddr = pg->aaddr;
1416                 if (pg->nat_proto != nat_proto)
1417                         continue;
1418
1419                 off = PG_GET_FREE_IDX(pg);
1420                 if (off != 0) {
1421                         /* We have found spare state. Use it */
1422                         off--;
1423                         PG_MARK_BUSY_IDX(pg, off);
1424                         st = &pg->states[off];
1425
1426                         /*
1427                          * Fill in new info. Assume state was zeroed.
1428                          * Timestamp and flags will be filled by caller.
1429                          */
1430                         st->u.s = kst->u.s;
1431                         st->cur.idx = i + 1;
1432                         st->cur.off = off;
1433
1434                         /* Insert into host hash table */
1435                         hval = HASH_IN4(&st->u.hkey) & (nh->hsize - 1);
1436                         st->next = nh->phash[hval];
1437                         nh->phash[hval] = st->cur;
1438
1439                         nat64lsn_dump_state(cfg, pg, st, "ALLOC STATE", off);
1440
1441                         NAT64STAT_INC(&cfg->base.stats, screated);
1442
1443                         return (st);
1444                 }
1445                 /* Saev last used alias affress */
1446                 *aaddr = pg->aaddr;
1447         }
1448
1449         return (NULL);
1450 }
1451
1452 static NAT64NOINLINE int
1453 nat64lsn_translate6(struct nat64lsn_cfg *cfg, struct ipfw_flow_id *f_id,
1454     struct mbuf **pm)
1455 {
1456         struct pfloghdr loghdr, *logdata;
1457         char a[INET6_ADDRSTRLEN];
1458         struct nat64lsn_host *nh;
1459         struct st_ptr sidx;
1460         struct nat64lsn_state *st, kst;
1461         struct nat64lsn_portgroup *pg;
1462         struct icmp6_hdr *icmp6;
1463         uint32_t aaddr;
1464         int action, hval, nat_proto, proto;
1465         uint16_t aport, state_ts, state_flags;
1466
1467         /* Check if af/protocol is supported and get it short id */
1468         nat_proto = nat64lsn_proto_map[f_id->proto];
1469         if (nat_proto == 0) {
1470                 /*
1471                  * Since we can be called from jobs handler, we need
1472                  * to free mbuf by self, do not leave this task to
1473                  * ipfw_check_packet().
1474                  */
1475                 NAT64STAT_INC(&cfg->base.stats, noproto);
1476                 goto drop;
1477         }
1478
1479         /* Try to find host first */
1480         I6HASH_FIND(cfg, nh, &f_id->src_ip6);
1481
1482         if (nh == NULL)
1483                 return (nat64lsn_request_host(cfg, f_id, pm));
1484
1485         /* Fill-in on-stack state structure */
1486         kst.u.s.faddr = nat64_extract_ip4(&f_id->dst_ip6,
1487             cfg->base.plat_plen);
1488         if (kst.u.s.faddr == 0 ||
1489             nat64_check_private_ip4(&cfg->base, kst.u.s.faddr) != 0) {
1490                 NAT64STAT_INC(&cfg->base.stats, dropped);
1491                 goto drop;
1492         }
1493         kst.u.s.fport = f_id->dst_port;
1494         kst.u.s.lport = f_id->src_port;
1495
1496         /* Prepare some fields we might need to update */
1497         hval = 0;
1498         proto = nat64_getlasthdr(*pm, &hval);
1499         if (proto < 0) {
1500                 NAT64STAT_INC(&cfg->base.stats, dropped);
1501                 DPRINTF(DP_DROPS, "dropped due to mbuf isn't contigious");
1502                 goto drop;
1503         }
1504
1505         SET_AGE(state_ts);
1506         if (proto == IPPROTO_TCP)
1507                 state_flags = convert_tcp_flags(
1508                     TCP(mtodo(*pm, hval))->th_flags);
1509         else
1510                 state_flags = 0;
1511         if (proto == IPPROTO_ICMPV6) {
1512                 /* Alter local port data */
1513                 icmp6 = mtodo(*pm, hval);
1514                 if (icmp6->icmp6_type == ICMP6_ECHO_REQUEST ||
1515                     icmp6->icmp6_type == ICMP6_ECHO_REPLY)
1516                         kst.u.s.lport = ntohs(icmp6->icmp6_id);
1517         }
1518
1519         hval = HASH_IN4(&kst.u.hkey) & (nh->hsize - 1);
1520         pg = NULL;
1521         st = NULL;
1522
1523         /* OK, let's find state in host hash */
1524         NAT64_LOCK(nh);
1525         sidx = nh->phash[hval];
1526         int k = 0;
1527         while (sidx.idx != 0) {
1528                 pg = PORTGROUP_BYSIDX(cfg, nh, sidx.idx);
1529                 st = &pg->states[sidx.off];
1530                 //DPRINTF("SISX: %d/%d next: %d/%d", sidx.idx, sidx.off,
1531                 //st->next.idx, st->next.off);
1532                 if (st->u.hkey == kst.u.hkey && pg->nat_proto == nat_proto)
1533                         break;
1534                 if (k++ > 1000) {
1535                         DPRINTF(DP_ALL, "XXX: too long %d/%d %d/%d\n",
1536                             sidx.idx, sidx.off, st->next.idx, st->next.off);
1537                         DPRINTF(DP_GENERIC, "TR host %s %p on cpu %d",
1538                             inet_ntop(AF_INET6, &nh->addr, a, sizeof(a)),
1539                             nh, curcpu);
1540                         k = 0;
1541                 }
1542                 sidx = st->next;
1543         }
1544
1545         if (sidx.idx == 0) {
1546                 aaddr = 0;
1547                 st = nat64lsn_create_state(cfg, nh, nat_proto, &kst, &aaddr);
1548                 if (st == NULL) {
1549                         /* No free states. Request more if we can */
1550                         if (nh->pg_used >= cfg->max_chunks) {
1551                                 /* Limit reached */
1552                                 DPRINTF(DP_DROPS, "PG limit reached "
1553                                     " for host %s (used %u, allocated %u, "
1554                                     "limit %u)", inet_ntop(AF_INET6,
1555                                     &nh->addr, a, sizeof(a)),
1556                                     nh->pg_used * NAT64_CHUNK_SIZE,
1557                                     nh->pg_allocated * NAT64_CHUNK_SIZE,
1558                                     cfg->max_chunks * NAT64_CHUNK_SIZE);
1559                                 NAT64_UNLOCK(nh);
1560                                 NAT64STAT_INC(&cfg->base.stats, dropped);
1561                                 goto drop;
1562                         }
1563                         if ((nh->pg_allocated <=
1564                             nh->pg_used + NAT64LSN_REMAININGPG) &&
1565                             nh->pg_allocated < cfg->max_chunks)
1566                                 action = 1; /* Request new indexes */
1567                         else
1568                                 action = 0;
1569                         NAT64_UNLOCK(nh);
1570                         //DPRINTF("No state, unlock for %p", nh);
1571                         return (nat64lsn_request_portgroup(cfg, f_id,
1572                             pm, aaddr, action));
1573                 }
1574
1575                 /* We've got new state. */
1576                 sidx = st->cur;
1577                 pg = PORTGROUP_BYSIDX(cfg, nh, sidx.idx);
1578         }
1579
1580         /* Okay, state found */
1581
1582         /* Update necessary fileds */
1583         if (st->timestamp != state_ts)
1584                 st->timestamp = state_ts;
1585         if ((st->flags & state_flags) != 0)
1586                 st->flags |= state_flags;
1587
1588         /* Copy needed state data */
1589         aaddr = pg->aaddr;
1590         aport = htons(pg->aport + sidx.off);
1591
1592         NAT64_UNLOCK(nh);
1593
1594         if (cfg->base.flags & NAT64_LOG) {
1595                 logdata = &loghdr;
1596                 nat64lsn_log(logdata, *pm, AF_INET6, pg->idx, st->cur.off);
1597         } else
1598                 logdata = NULL;
1599
1600         action = nat64_do_handle_ip6(*pm, aaddr, aport, &cfg->base, logdata);
1601         if (action == NAT64SKIP)
1602                 return (cfg->nomatch_verdict);
1603         if (action == NAT64MFREE) {
1604 drop:
1605                 m_freem(*pm);
1606         }
1607         *pm = NULL;     /* mark mbuf as consumed */
1608         return (IP_FW_DENY);
1609 }
1610
1611 /*
1612  * Main dataplane entry point.
1613  */
1614 int
1615 ipfw_nat64lsn(struct ip_fw_chain *ch, struct ip_fw_args *args,
1616     ipfw_insn *cmd, int *done)
1617 {
1618         ipfw_insn *icmd;
1619         struct nat64lsn_cfg *cfg;
1620         int ret;
1621
1622         IPFW_RLOCK_ASSERT(ch);
1623
1624         *done = 1; /* terminate the search */
1625         icmd = cmd + 1;
1626         if (cmd->opcode != O_EXTERNAL_ACTION ||
1627             cmd->arg1 != V_nat64lsn_eid ||
1628             icmd->opcode != O_EXTERNAL_INSTANCE ||
1629             (cfg = NAT64_LOOKUP(ch, icmd)) == NULL)
1630                 return (0);
1631
1632         switch (args->f_id.addr_type) {
1633         case 4:
1634                 ret = nat64lsn_translate4(cfg, &args->f_id, &args->m);
1635                 break;
1636         case 6:
1637                 ret = nat64lsn_translate6(cfg, &args->f_id, &args->m);
1638                 break;
1639         default:
1640                 return (cfg->nomatch_verdict);
1641         }
1642         return (ret);
1643 }
1644
1645 static int
1646 nat64lsn_ctor_host(void *mem, int size, void *arg, int flags)
1647 {
1648         struct nat64lsn_host *nh;
1649
1650         nh = (struct nat64lsn_host *)mem;
1651         memset(nh->pg_ptr, 0, sizeof(nh->pg_ptr));
1652         memset(nh->phash, 0, sizeof(nh->phash));
1653         return (0);
1654 }
1655
1656 static int
1657 nat64lsn_ctor_pgidx(void *mem, int size, void *arg, int flags)
1658 {
1659
1660         memset(mem, 0, size);
1661         return (0);
1662 }
1663
1664 void
1665 nat64lsn_init_internal(void)
1666 {
1667
1668         memset(nat64lsn_proto_map, 0, sizeof(nat64lsn_proto_map));
1669         /* Set up supported protocol map */
1670         nat64lsn_proto_map[IPPROTO_TCP] = NAT_PROTO_TCP;
1671         nat64lsn_proto_map[IPPROTO_UDP] = NAT_PROTO_UDP;
1672         nat64lsn_proto_map[IPPROTO_ICMP] = NAT_PROTO_ICMP;
1673         nat64lsn_proto_map[IPPROTO_ICMPV6] = NAT_PROTO_ICMP;
1674         /* Fill in reverse proto map */
1675         memset(nat64lsn_rproto_map, 0, sizeof(nat64lsn_rproto_map));
1676         nat64lsn_rproto_map[NAT_PROTO_TCP] = IPPROTO_TCP;
1677         nat64lsn_rproto_map[NAT_PROTO_UDP] = IPPROTO_UDP;
1678         nat64lsn_rproto_map[NAT_PROTO_ICMP] = IPPROTO_ICMPV6;
1679
1680         JQUEUE_LOCK_INIT();
1681         nat64lsn_host_zone = uma_zcreate("NAT64 hosts zone",
1682             sizeof(struct nat64lsn_host), nat64lsn_ctor_host, NULL,
1683             NULL, NULL, UMA_ALIGN_PTR, 0);
1684         nat64lsn_pg_zone = uma_zcreate("NAT64 portgroups zone",
1685             sizeof(struct nat64lsn_portgroup), NULL, NULL, NULL, NULL,
1686             UMA_ALIGN_PTR, 0);
1687         nat64lsn_pgidx_zone = uma_zcreate("NAT64 portgroup indexes zone",
1688             sizeof(struct nat64lsn_portgroup *) * NAT64LSN_PGIDX_CHUNK,
1689             nat64lsn_ctor_pgidx, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
1690 }
1691
1692 void
1693 nat64lsn_uninit_internal(void)
1694 {
1695
1696         JQUEUE_LOCK_DESTROY();
1697         uma_zdestroy(nat64lsn_host_zone);
1698         uma_zdestroy(nat64lsn_pg_zone);
1699         uma_zdestroy(nat64lsn_pgidx_zone);
1700 }
1701
1702 void
1703 nat64lsn_start_instance(struct nat64lsn_cfg *cfg)
1704 {
1705
1706         callout_reset(&cfg->periodic, hz * PERIODIC_DELAY,
1707             nat64lsn_periodic, cfg);
1708 }
1709
1710 struct nat64lsn_cfg *
1711 nat64lsn_init_instance(struct ip_fw_chain *ch, size_t numaddr)
1712 {
1713         struct nat64lsn_cfg *cfg;
1714
1715         cfg = malloc(sizeof(struct nat64lsn_cfg), M_IPFW, M_WAITOK | M_ZERO);
1716         TAILQ_INIT(&cfg->jhead);
1717         cfg->vp = curvnet;
1718         cfg->ch = ch;
1719         COUNTER_ARRAY_ALLOC(cfg->base.stats.cnt, NAT64STATS, M_WAITOK);
1720
1721         cfg->ihsize = NAT64LSN_HSIZE;
1722         cfg->ih = malloc(sizeof(void *) * cfg->ihsize, M_IPFW,
1723             M_WAITOK | M_ZERO);
1724
1725         cfg->pg = malloc(sizeof(void *) * numaddr * _ADDR_PG_COUNT, M_IPFW,
1726             M_WAITOK | M_ZERO);
1727
1728         callout_init(&cfg->periodic, CALLOUT_MPSAFE);
1729         callout_init(&cfg->jcallout, CALLOUT_MPSAFE);
1730
1731         return (cfg);
1732 }
1733
1734 /*
1735  * Destroy all hosts callback.
1736  * Called on module unload when all activity already finished, so
1737  * can work without any locks.
1738  */
1739 static NAT64NOINLINE int
1740 nat64lsn_destroy_host(struct nat64lsn_host *nh, struct nat64lsn_cfg *cfg)
1741 {
1742         struct nat64lsn_portgroup *pg;
1743         int i;
1744
1745         for (i = nh->pg_used; i > 0; i--) {
1746                 pg = PORTGROUP_BYSIDX(cfg, nh, i);
1747                 if (pg == NULL)
1748                         continue;
1749                 cfg->pg[pg->idx] = NULL;
1750                 destroy_portgroup(pg);
1751                 nh->pg_used--;
1752         }
1753         destroy_host6(nh);
1754         cfg->ihcount--;
1755         return (0);
1756 }
1757
1758 void
1759 nat64lsn_destroy_instance(struct nat64lsn_cfg *cfg)
1760 {
1761         struct nat64lsn_host *nh, *tmp;
1762
1763         callout_drain(&cfg->jcallout);
1764         callout_drain(&cfg->periodic);
1765         I6HASH_FOREACH_SAFE(cfg, nh, tmp, nat64lsn_destroy_host, cfg);
1766         DPRINTF(DP_OBJ, "instance %s: hosts %d", cfg->name, cfg->ihcount);
1767
1768         COUNTER_ARRAY_FREE(cfg->base.stats.cnt, NAT64STATS);
1769         free(cfg->ih, M_IPFW);
1770         free(cfg->pg, M_IPFW);
1771         free(cfg, M_IPFW);
1772 }
1773