2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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.
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
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>
39 #include <sys/malloc.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>
50 #include <net/if_var.h>
51 #include <net/if_pflog.h>
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>
67 #include <netpfil/ipfw/ip_fw_private.h>
68 #include <netpfil/pf/pf.h>
72 MALLOC_DEFINE(M_NAT64LSN, "NAT64LSN", "NAT64LSN");
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];
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)
84 #define NAT64_FLAG_RDR 0x80 /* Port redirect */
85 #define NAT64_LOOKUP(chain, cmd) \
86 (struct nat64lsn_cfg *)SRV_OBJECT((chain), (cmd)->arg1)
88 * Delayed job queue, used to create new hosts
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;
103 struct in6_addr haddr;
108 unsigned int fhash; /* Flow hash */
109 uint32_t aaddr; /* Last used address (net) */
111 struct ipfw_flow_id f_id;
112 uint64_t delmask[NAT64LSN_PGPTRNMASK];
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)
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);
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,
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);
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);
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);
149 static uma_zone_t nat64lsn_host_zone;
150 static uma_zone_t nat64lsn_pg_zone;
151 static uma_zone_t nat64lsn_pgidx_zone;
153 static unsigned int nat64lsn_periodic_chkstates(struct nat64lsn_cfg *cfg,
154 struct nat64lsn_host *nh);
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)
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)
171 #define I6HASH_FOREACH_SAFE(_cfg, _x, _tmp, _cb, _arg) \
172 CHT_FOREACH_SAFE(_cfg->ih, _cfg->ihsize, I6_, _x, _tmp, _cb, _arg)
174 #define HASH_IN4(x) djb_hash((const unsigned char *)(x), 8)
177 djb_hash(const unsigned char *h, const int len)
179 unsigned int result = 0;
182 for (i = 0; i < len; i++)
183 result = 33 * result ^ h[i];
190 bitmask_size(size_t num, int *level)
195 for (c = 0, x = num; num > 1; num /= 64, c++)
202 bitmask_prepare(uint64_t *pmask, size_t bufsize, int level)
206 memset(pmask, 0xFF, bufsize);
207 for (x = 0, z = 1; level > 1; x += z, z *= 64, level--)
214 nat64lsn_log(struct pfloghdr *plog, struct mbuf *m, sa_family_t family,
215 uint32_t n, uint32_t sn)
218 memset(plog, 0, sizeof(*plog));
219 plog->length = PFLOG_REAL_HDRLEN;
221 plog->action = PF_NAT;
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);
230 * Inspects icmp packets to see if the message contains different
231 * packet header so we need to alter @addr and @port.
234 inspect_icmp_mbuf(struct mbuf **m, uint8_t *nat_proto, uint32_t *addr,
240 struct icmphdr *icmp;
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);
251 ip = mtod(*m, struct ip *); /* Outer IP header */
252 icmp = L3HDR(ip, struct icmphdr *);
253 switch (icmp->icmp_type) {
256 /* Use icmp ID as distinguisher */
257 *port = ntohs(*((uint16_t *)(icmp + 1)));
266 * ICMP_UNREACH and ICMP_TIMXCEED contains IP header + 64 bits
269 if ((*m)->m_pkthdr.len < off + sizeof(struct ip) + ICMP_MINLEN)
271 if ((*m)->m_len < off + sizeof(struct ip) + ICMP_MINLEN)
272 *m = m_pullup(*m, off + sizeof(struct ip) + ICMP_MINLEN);
275 ip = mtodo(*m, off); /* Inner IP header */
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);
285 tcp = mtodo(*m, off);
286 *nat_proto = NAT_PROTO_TCP;
287 *port = ntohs(tcp->th_sport);
290 udp = mtodo(*m, off);
291 *nat_proto = NAT_PROTO_UDP;
292 *port = ntohs(udp->uh_sport);
296 * We will translate only ICMP errors for our ICMP
299 icmp = mtodo(*m, off);
300 if (icmp->icmp_type != ICMP_ECHO)
302 *port = ntohs(*((uint16_t *)(icmp + 1)));
308 static inline uint8_t
309 convert_tcp_flags(uint8_t flags)
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 */
320 static NAT64NOINLINE int
321 nat64lsn_translate4(struct nat64lsn_cfg *cfg, const struct ipfw_flow_id *f_id,
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;
331 uint16_t state_flags, state_ts;
332 uint16_t port, lport;
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);
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);
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);
355 NAT64STAT_INC(&cfg->base.stats, nomem);
358 NAT64STAT_INC(&cfg->base.stats, noproto);
359 return (cfg->nomatch_verdict);
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);
368 /* Calc portgroup offset w.r.t protocol */
369 pg = GET_PORTGROUP(cfg, addr, nat_proto, port);
371 /* Check if this port is occupied by any portgroup */
373 NAT64STAT_INC(&cfg->base.stats, nomatch4);
375 DPRINTF(DP_STATE, "NOMATCH %u %d %d (%d)", addr, nat_proto, port,
376 _GET_PORTGROUP_IDX(cfg, addr, nat_proto, port));
378 return (cfg->nomatch_verdict);
381 /* TODO: Check flags to see if we need to do some static mapping */
384 /* Prepare some fields we might need to update */
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);
393 /* Lock host and get port mapping */
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);
405 if (cfg->base.flags & NAT64_LOG) {
407 nat64lsn_log(logdata, *pm, AF_INET, pg->idx, st->cur.off);
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);
416 if (ret == NAT64SKIP)
417 return (cfg->nomatch_verdict);
418 if (ret == NAT64MFREE)
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)
430 char s[INET6_ADDRSTRLEN], a[INET_ADDRSTRLEN], d[INET_ADDRSTRLEN];
432 if ((V_nat64_debug & DP_STATE) == 0)
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));
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));
445 * Check if particular TCP state is stale and should be deleted.
446 * Return 1 if true, 0 otherwise.
449 nat64lsn_periodic_check_tcp(const struct nat64lsn_cfg *cfg,
450 const struct nat64lsn_state *st, int age)
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;
461 ttl = cfg->st_syn_ttl;
469 * Check if nat state @st is stale and should be deleted.
470 * Return 1 if true, 0 otherwise.
472 static NAT64NOINLINE int
473 nat64lsn_periodic_chkstate(const struct nat64lsn_cfg *cfg,
474 const struct nat64lsn_portgroup *pg, const struct nat64lsn_state *st)
478 age = GET_AGE(st->timestamp);
481 /* Skip immutable records */
482 if (st->flags & NAT64_FLAG_RDR)
485 switch (pg->nat_proto) {
487 delete = nat64lsn_periodic_check_tcp(cfg, st, age);
490 if (age > cfg->st_udp_ttl)
494 if (age > cfg->st_icmp_ttl)
504 * The following structures and functions
505 * are used to perform SLIST_FOREACH_SAFE()
506 * analog for states identified by struct st_ptr.
510 struct nat64lsn_portgroup *pg;
511 struct nat64lsn_state *st;
512 struct st_ptr sidx_next;
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)
519 struct nat64lsn_portgroup *pg;
520 struct nat64lsn_state *st;
522 if (sidx->idx == 0) {
523 memset(si, 0, sizeof(*si));
527 pg = PORTGROUP_BYSIDX(cfg, nh, sidx->idx);
528 st = &pg->states[sidx->off];
532 si->sidx_next = st->next;
537 static struct st_idx *
538 st_next(const struct nat64lsn_cfg *cfg, const struct nat64lsn_host *nh,
542 struct nat64lsn_portgroup *pg;
543 struct nat64lsn_state *st;
545 sidx = si->sidx_next;
547 memset(si, 0, sizeof(*si));
553 pg = PORTGROUP_BYSIDX(cfg, nh, sidx.idx);
554 st = &pg->states[sidx.off];
558 si->sidx_next = st->next;
563 static struct st_idx *
564 st_save_cond(struct st_idx *si_dst, struct st_idx *si)
573 nat64lsn_periodic_chkstates(struct nat64lsn_cfg *cfg, struct nat64lsn_host *nh)
575 struct st_idx si, si_prev;
577 unsigned int delcount;
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);
584 st_save_cond(&si_prev, &si), st_next(cfg, nh, &si)) {
585 if (nat64lsn_periodic_chkstate(cfg, si.pg, si.st) == 0)
587 nat64lsn_dump_state(cfg, si.pg, si.st, "DELETE STATE",
589 /* Unlink from hash */
590 if (si_prev.st != NULL)
591 si_prev.st->next = si.st->next;
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));
600 /* Update portgroup timestamp */
601 SET_AGE(si.pg->timestamp);
604 NAT64STAT_ADD(&cfg->base.stats, sdeleted, delcount);
609 * Checks if portgroup is not used and can be deleted,
610 * Returns 1 if stale, 0 otherwise
613 stale_pg(const struct nat64lsn_cfg *cfg, const struct nat64lsn_portgroup *pg)
616 if (!PG_IS_EMPTY(pg))
618 if (GET_AGE(pg->timestamp) < cfg->pg_delete_delay)
624 * Checks if host record is not used and can be deleted,
625 * Returns 1 if stale, 0 otherwise
628 stale_nh(const struct nat64lsn_cfg *cfg, const struct nat64lsn_host *nh)
631 if (nh->pg_used != 0)
633 if (GET_AGE(nh->timestamp) < cfg->nh_delete_delay)
638 struct nat64lsn_periodic_data {
639 struct nat64lsn_cfg *cfg;
640 struct nat64lsn_job_head jhead;
644 static NAT64NOINLINE int
645 nat64lsn_periodic_chkhost(struct nat64lsn_host *nh,
646 struct nat64lsn_periodic_data *d)
648 struct nat64lsn_portgroup *pg;
649 struct nat64lsn_job_item *ji;
650 uint64_t delmask[NAT64LSN_PGPTRNMASK];
654 memset(delmask, 0, sizeof(delmask));
656 if (V_nat64_debug & DP_JQUEUE) {
657 char a[INET6_ADDRSTRLEN];
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);
663 if (!stale_nh(d->cfg, nh)) {
664 /* Non-stale host. Inspect internals */
667 /* Stage 1: Check&expire states */
668 if (nat64lsn_periodic_chkstates(d->cfg, nh) != 0)
669 SET_AGE(nh->timestamp);
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);
677 /* Check if we can delete portgroup */
678 if (stale_pg(d->cfg, pg) == 0)
681 DPRINTF(DP_JQUEUE, "Check PG %d", i);
682 delmask[i / 64] |= ((uint64_t)1 << (i % 64));
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);
697 ji->haddr = nh->addr;
698 ji->delcount = delcount;
699 memcpy(ji->delmask, delmask, sizeof(ji->delmask));
701 TAILQ_INSERT_TAIL(&d->jhead, ji, next);
707 * This procedure is used to perform various maintance
708 * on dynamic hash list. Currently it is called every second.
711 nat64lsn_periodic(void *data)
713 struct ip_fw_chain *ch;
715 struct nat64lsn_cfg *cfg;
716 struct nat64lsn_periodic_data d;
717 struct nat64lsn_host *nh, *tmp;
719 cfg = (struct nat64lsn_cfg *) data;
721 CURVNET_SET(cfg->vp);
723 memset(&d, 0, sizeof(d));
725 TAILQ_INIT(&d.jhead);
729 /* Stage 1: foreach host, check all its portgroups */
730 I6HASH_FOREACH_SAFE(cfg, nh, tmp, nat64lsn_periodic_chkhost, &d);
732 /* Enqueue everything we have requested */
733 nat64lsn_enqueue_jobs(cfg, &d.jhead, d.jlen);
735 callout_schedule(&cfg->periodic, hz * PERIODIC_DELAY);
742 static NAT64NOINLINE void
743 reinject_mbuf(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
749 /* Request has failed or packet type is wrong */
750 if (ji->f_id.addr_type != 6 || ji->done == 0) {
753 NAT64STAT_INC(&cfg->base.stats, dropped);
754 DPRINTF(DP_DROPS, "mbuf dropped: type %d, done %d",
755 ji->jtype, ji->done);
760 * XXX: Limit recursion level
763 NAT64STAT_INC(&cfg->base.stats, jreinjected);
764 DPRINTF(DP_JQUEUE, "Reinject mbuf");
765 nat64lsn_translate6(cfg, &ji->f_id, &ji->m);
769 destroy_portgroup(struct nat64lsn_portgroup *pg)
772 DPRINTF(DP_OBJ, "DESTROY PORTGROUP %d %p", pg->idx, pg);
773 uma_zfree(nat64lsn_pg_zone, pg);
776 static NAT64NOINLINE int
777 alloc_portgroup(struct nat64lsn_job_item *ji)
779 struct nat64lsn_portgroup *pg;
781 pg = uma_zalloc(nat64lsn_pg_zone, M_NOWAIT);
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 */
789 memset(&pg->freemask, 0xFF, sizeof(pg->freemask));
790 pg->nat_proto = ji->nat_proto;
797 destroy_host6(struct nat64lsn_host *nh)
799 char a[INET6_ADDRSTRLEN];
802 inet_ntop(AF_INET6, &nh->addr, a, sizeof(a));
803 DPRINTF(DP_OBJ, "DESTROY HOST %s %p (pg used %d)", a, nh,
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);
811 static NAT64NOINLINE int
812 alloc_host6(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
814 struct nat64lsn_host *nh;
815 char a[INET6_ADDRSTRLEN];
817 nh = uma_zalloc(nat64lsn_host_zone, M_NOWAIT);
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);
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);
833 nh->addr = ji->haddr;
834 nh->hsize = NAT64LSN_HSIZE; /* XXX: hardcoded size */
835 nh->pg_allocated = NAT64LSN_PGIDX_CHUNK;
839 inet_ntop(AF_INET6, &nh->addr, a, sizeof(a));
840 DPRINTF(DP_OBJ, "ALLOC HOST %s %p", a, ji->nh);
845 * Finds free @pg index inside @nh
847 static NAT64NOINLINE int
848 find_nh_pg_idx(struct nat64lsn_cfg *cfg, struct nat64lsn_host *nh, int *idx)
852 for (i = 0; i < nh->pg_allocated; i++) {
853 if (PORTGROUP_BYSIDX(cfg, nh, i + 1) == NULL) {
861 static NAT64NOINLINE int
862 attach_host6(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
864 char a[INET6_ADDRSTRLEN];
865 struct nat64lsn_host *nh;
867 I6HASH_FIND(cfg, nh, &ji->haddr);
869 /* Add new host to list */
871 I6HASH_INSERT(cfg, nh);
875 inet_ntop(AF_INET6, &nh->addr, a, sizeof(a));
876 DPRINTF(DP_OBJ, "ATTACH HOST %s %p", a, nh);
878 * Try to add portgroup.
879 * Note it will automatically set
880 * 'done' on ji if successful.
882 if (attach_portgroup(cfg, ji) != 0) {
883 DPRINTF(DP_DROPS, "%s %p failed to attach PG",
885 NAT64STAT_INC(&cfg->base.stats, jportfails);
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.
898 inet_ntop(AF_INET6, &nh->addr, a, sizeof(a));
899 DPRINTF(DP_OBJ, "%s %p is already attached as %p",
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)
911 pg_idx = addr_off * _ADDR_PG_COUNT +
912 (nat_proto - 1) * _ADDR_PG_PROTO_COUNT;
914 for (j = NAT64_MIN_CHUNK; j < _ADDR_PG_PROTO_COUNT; j++) {
915 if (cfg->pg[pg_idx + j] != NULL)
918 *aport = j * NAT64_CHUNK_SIZE;
919 *ppg_idx = pg_idx + j;
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
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)
941 * XXX: Use bitmask index to be able to find/check if IP address
942 * has some spare pg's
944 nat_proto = ji->nat_proto;
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,
952 *aaddr = htonl(cfg->prefix4 + i);
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) {
961 *aaddr = htonl(cfg->prefix4 + i);
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,
971 *aaddr = htonl(cfg->prefix4 + i);
979 static NAT64NOINLINE int
980 attach_portgroup(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
982 char a[INET6_ADDRSTRLEN];
983 struct nat64lsn_portgroup *pg;
984 struct nat64lsn_host *nh;
987 int nh_pg_idx, pg_idx;
992 * Find source host and bind: we can't rely on
995 I6HASH_FIND(cfg, nh, &ji->haddr);
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);
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) =
1010 nh->pg_allocated += NAT64LSN_PGIDX_CHUNK;
1011 ji->spare_idx = NULL;
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",
1022 cfg->pg[pg_idx] = pg;
1023 cfg->protochunks[pg->nat_proto]++;
1024 NAT64STAT_INC(&cfg->base.stats, spgcreated);
1030 SET_AGE(pg->timestamp);
1032 PORTGROUP_BYSIDX(cfg, nh, nh_pg_idx + 1) = pg;
1033 if (nh->pg_used == nh_pg_idx)
1035 SET_AGE(nh->timestamp);
1043 static NAT64NOINLINE void
1044 consider_del_portgroup(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
1046 struct nat64lsn_host *nh, *nh_tmp;
1047 struct nat64lsn_portgroup *pg, *pg_list[256];
1048 int i, pg_lidx, idx;
1050 /* Find source host */
1051 I6HASH_FIND(cfg, nh, &ji->haddr);
1052 if (nh == NULL || nh->pg_used == 0)
1055 memset(pg_list, 0, sizeof(pg_list));
1060 for (i = nh->pg_used - 1; i >= 0; i--) {
1061 if ((ji->delmask[i / 64] & ((uint64_t)1 << (i % 64))) == 0)
1063 pg = PORTGROUP_BYSIDX(cfg, nh, i + 1);
1065 /* Check that PG isn't busy. */
1066 if (stale_pg(cfg, pg) == 0)
1070 pg_list[pg_lidx++] = pg;
1071 PORTGROUP_BYSIDX(cfg, nh, i + 1) = NULL;
1073 idx = _GET_PORTGROUP_IDX(cfg, ntohl(pg->aaddr), pg->nat_proto,
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);
1080 /* Decrease pg_used */
1081 while (nh->pg_used > 0 &&
1082 PORTGROUP_BYSIDX(cfg, nh, nh->pg_used) == NULL)
1085 /* Check if on-stack buffer has ended */
1086 if (pg_lidx == nitems(pg_list))
1092 if (stale_nh(cfg, nh)) {
1093 I6HASH_REMOVE(cfg, nh, nh_tmp, &ji->haddr);
1094 KASSERT(nh != NULL, ("Unable to find address"));
1097 I6HASH_FIND(cfg, nh, &ji->haddr);
1098 KASSERT(nh == NULL, ("Failed to delete address"));
1101 /* TODO: Delay freeing portgroups */
1102 while (pg_lidx > 0) {
1104 NAT64STAT_INC(&cfg->base.stats, spgdeleted);
1105 destroy_portgroup(pg_list[pg_lidx]);
1110 * Main request handler.
1111 * Responsible for handling jqueue, e.g.
1112 * creating new hosts, addind/deleting portgroups.
1114 static NAT64NOINLINE void
1115 nat64lsn_do_request(void *data)
1118 struct nat64lsn_job_head jhead;
1119 struct nat64lsn_job_item *ji;
1121 struct nat64lsn_cfg *cfg = (struct nat64lsn_cfg *) data;
1122 struct ip_fw_chain *ch;
1125 CURVNET_SET(cfg->vp);
1129 /* XXX: We're running unlocked here */
1137 TAILQ_SWAP(&jhead, &cfg->jhead, nat64lsn_job_item, next);
1142 /* check if we need to resize hash */
1144 if (cfg->ihcount > cfg->ihsize && cfg->ihsize < 65536) {
1145 nhsize = cfg->ihsize;
1146 for ( ; cfg->ihcount > nhsize && nhsize < 65536; nhsize *= 2)
1148 } else if (cfg->ihcount < cfg->ihsize * 4) {
1149 nhsize = cfg->ihsize;
1150 for ( ; cfg->ihcount < nhsize * 4 && nhsize > 32; nhsize /= 2)
1156 if (TAILQ_EMPTY(&jhead)) {
1161 NAT64STAT_INC(&cfg->base.stats, jcalls);
1162 DPRINTF(DP_JQUEUE, "count=%d", jcount);
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.
1170 * TODO: Limit per-call number of items
1173 /* Pre-allocate everything for entire chain */
1174 TAILQ_FOREACH(ji, &jhead, next) {
1175 switch (ji->jtype) {
1177 if (alloc_host6(cfg, ji) != 0)
1178 NAT64STAT_INC(&cfg->base.stats,
1181 case JTYPE_NEWPORTGROUP:
1182 if (alloc_portgroup(ji) != 0)
1183 NAT64STAT_INC(&cfg->base.stats,
1186 case JTYPE_DELPORTGROUP:
1187 delcount += ji->delcount;
1195 * TODO: Alloc hew hash
1202 /* Apply all changes in batch */
1206 TAILQ_FOREACH(ji, &jhead, next) {
1207 switch (ji->jtype) {
1210 attach_host6(cfg, ji);
1212 case JTYPE_NEWPORTGROUP:
1213 if (ji->pg != NULL &&
1214 attach_portgroup(cfg, ji) != 0)
1215 NAT64STAT_INC(&cfg->base.stats,
1218 case JTYPE_DELPORTGROUP:
1219 consider_del_portgroup(cfg, ji);
1225 /* XXX: Move everything to new hash */
1229 IPFW_UH_WUNLOCK(ch);
1231 /* Flush unused entries */
1232 while (!TAILQ_EMPTY(&jhead)) {
1233 ji = TAILQ_FIRST(&jhead);
1234 TAILQ_REMOVE(&jhead, ji, next);
1236 destroy_host6(ji->nh);
1238 destroy_portgroup(ji->pg);
1240 reinject_mbuf(cfg, ji);
1241 if (ji->spare_idx != NULL)
1242 uma_zfree(nat64lsn_pgidx_zone, ji->spare_idx);
1248 static NAT64NOINLINE struct nat64lsn_job_item *
1249 nat64lsn_create_job(struct nat64lsn_cfg *cfg, const struct ipfw_flow_id *f_id,
1252 struct nat64lsn_job_item *ji;
1253 struct in6_addr haddr;
1257 * Do not try to lock possibly contested mutex if we're near the limit.
1258 * Drop packet instead.
1260 if (cfg->jlen >= cfg->jmaxlen) {
1261 NAT64STAT_INC(&cfg->base.stats, jmaxlen);
1265 memset(&haddr, 0, sizeof(haddr));
1268 haddr = f_id->src_ip6;
1269 nat_proto = nat64lsn_proto_map[f_id->proto];
1271 DPRINTF(DP_JQUEUE, "REQUEST pg nat_proto %d on proto %d",
1272 nat_proto, f_id->proto);
1278 ji = malloc(sizeof(struct nat64lsn_job_item), M_IPFW,
1282 NAT64STAT_INC(&cfg->base.stats, jnomem);
1291 ji->nat_proto = nat_proto;
1297 static NAT64NOINLINE void
1298 nat64lsn_enqueue_job(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
1305 TAILQ_INSERT_TAIL(&cfg->jhead, ji, next);
1307 NAT64STAT_INC(&cfg->base.stats, jrequests);
1309 if (callout_pending(&cfg->jcallout) == 0)
1310 callout_reset(&cfg->jcallout, 1, nat64lsn_do_request, cfg);
1314 static NAT64NOINLINE void
1315 nat64lsn_enqueue_jobs(struct nat64lsn_cfg *cfg,
1316 struct nat64lsn_job_head *jhead, int jlen)
1319 if (TAILQ_EMPTY(jhead))
1322 /* Attach current queue to execution one */
1324 TAILQ_CONCAT(&cfg->jhead, jhead, next);
1326 NAT64STAT_ADD(&cfg->base.stats, jrequests, jlen);
1328 if (callout_pending(&cfg->jcallout) == 0)
1329 callout_reset(&cfg->jcallout, 1, nat64lsn_do_request, cfg);
1334 flow6_hash(const struct ipfw_flow_id *f_id)
1336 unsigned char hbuf[36];
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);
1343 return (djb_hash(hbuf, sizeof(hbuf)));
1346 static NAT64NOINLINE int
1347 nat64lsn_request_host(struct nat64lsn_cfg *cfg,
1348 const struct ipfw_flow_id *f_id, struct mbuf **pm)
1350 struct nat64lsn_job_item *ji;
1356 ji = nat64lsn_create_job(cfg, f_id, JTYPE_NEWHOST);
1359 NAT64STAT_INC(&cfg->base.stats, dropped);
1360 DPRINTF(DP_DROPS, "failed to create job");
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);
1369 return (IP_FW_DENY);
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,
1377 struct nat64lsn_job_item *ji;
1383 ji = nat64lsn_create_job(cfg, f_id, JTYPE_NEWPORTGROUP);
1386 NAT64STAT_INC(&cfg->base.stats, dropped);
1387 DPRINTF(DP_DROPS, "failed to create job");
1390 /* Provide pseudo-random value based on flow */
1391 ji->fhash = flow6_hash(f_id);
1393 ji->needs_idx = needs_idx;
1394 nat64lsn_enqueue_job(cfg, ji);
1395 NAT64STAT_INC(&cfg->base.stats, jportreq);
1398 return (IP_FW_DENY);
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)
1405 struct nat64lsn_portgroup *pg;
1406 struct nat64lsn_state *st;
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);
1416 if (pg->nat_proto != nat_proto)
1419 off = PG_GET_FREE_IDX(pg);
1421 /* We have found spare state. Use it */
1423 PG_MARK_BUSY_IDX(pg, off);
1424 st = &pg->states[off];
1427 * Fill in new info. Assume state was zeroed.
1428 * Timestamp and flags will be filled by caller.
1431 st->cur.idx = i + 1;
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;
1439 nat64lsn_dump_state(cfg, pg, st, "ALLOC STATE", off);
1441 NAT64STAT_INC(&cfg->base.stats, screated);
1445 /* Saev last used alias affress */
1452 static NAT64NOINLINE int
1453 nat64lsn_translate6(struct nat64lsn_cfg *cfg, struct ipfw_flow_id *f_id,
1456 struct pfloghdr loghdr, *logdata;
1457 char a[INET6_ADDRSTRLEN];
1458 struct nat64lsn_host *nh;
1460 struct nat64lsn_state *st, kst;
1461 struct nat64lsn_portgroup *pg;
1462 struct icmp6_hdr *icmp6;
1464 int action, hval, nat_proto, proto;
1465 uint16_t aport, state_ts, state_flags;
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) {
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().
1475 NAT64STAT_INC(&cfg->base.stats, noproto);
1479 /* Try to find host first */
1480 I6HASH_FIND(cfg, nh, &f_id->src_ip6);
1483 return (nat64lsn_request_host(cfg, f_id, pm));
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);
1493 kst.u.s.fport = f_id->dst_port;
1494 kst.u.s.lport = f_id->src_port;
1496 /* Prepare some fields we might need to update */
1498 proto = nat64_getlasthdr(*pm, &hval);
1500 NAT64STAT_INC(&cfg->base.stats, dropped);
1501 DPRINTF(DP_DROPS, "dropped due to mbuf isn't contigious");
1506 if (proto == IPPROTO_TCP)
1507 state_flags = convert_tcp_flags(
1508 TCP(mtodo(*pm, hval))->th_flags);
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);
1519 hval = HASH_IN4(&kst.u.hkey) & (nh->hsize - 1);
1523 /* OK, let's find state in host hash */
1525 sidx = nh->phash[hval];
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)
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)),
1545 if (sidx.idx == 0) {
1547 st = nat64lsn_create_state(cfg, nh, nat_proto, &kst, &aaddr);
1549 /* No free states. Request more if we can */
1550 if (nh->pg_used >= cfg->max_chunks) {
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);
1560 NAT64STAT_INC(&cfg->base.stats, dropped);
1563 if ((nh->pg_allocated <=
1564 nh->pg_used + NAT64LSN_REMAININGPG) &&
1565 nh->pg_allocated < cfg->max_chunks)
1566 action = 1; /* Request new indexes */
1570 //DPRINTF("No state, unlock for %p", nh);
1571 return (nat64lsn_request_portgroup(cfg, f_id,
1572 pm, aaddr, action));
1575 /* We've got new state. */
1577 pg = PORTGROUP_BYSIDX(cfg, nh, sidx.idx);
1580 /* Okay, state found */
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;
1588 /* Copy needed state data */
1590 aport = htons(pg->aport + sidx.off);
1594 if (cfg->base.flags & NAT64_LOG) {
1596 nat64lsn_log(logdata, *pm, AF_INET6, pg->idx, st->cur.off);
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) {
1607 *pm = NULL; /* mark mbuf as consumed */
1608 return (IP_FW_DENY);
1612 * Main dataplane entry point.
1615 ipfw_nat64lsn(struct ip_fw_chain *ch, struct ip_fw_args *args,
1616 ipfw_insn *cmd, int *done)
1619 struct nat64lsn_cfg *cfg;
1622 IPFW_RLOCK_ASSERT(ch);
1624 *done = 1; /* terminate the search */
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)
1632 switch (args->f_id.addr_type) {
1634 ret = nat64lsn_translate4(cfg, &args->f_id, &args->m);
1637 ret = nat64lsn_translate6(cfg, &args->f_id, &args->m);
1640 return (cfg->nomatch_verdict);
1646 nat64lsn_ctor_host(void *mem, int size, void *arg, int flags)
1648 struct nat64lsn_host *nh;
1650 nh = (struct nat64lsn_host *)mem;
1651 memset(nh->pg_ptr, 0, sizeof(nh->pg_ptr));
1652 memset(nh->phash, 0, sizeof(nh->phash));
1657 nat64lsn_ctor_pgidx(void *mem, int size, void *arg, int flags)
1660 memset(mem, 0, size);
1665 nat64lsn_init_internal(void)
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;
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,
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);
1693 nat64lsn_uninit_internal(void)
1696 JQUEUE_LOCK_DESTROY();
1697 uma_zdestroy(nat64lsn_host_zone);
1698 uma_zdestroy(nat64lsn_pg_zone);
1699 uma_zdestroy(nat64lsn_pgidx_zone);
1703 nat64lsn_start_instance(struct nat64lsn_cfg *cfg)
1706 callout_reset(&cfg->periodic, hz * PERIODIC_DELAY,
1707 nat64lsn_periodic, cfg);
1710 struct nat64lsn_cfg *
1711 nat64lsn_init_instance(struct ip_fw_chain *ch, size_t numaddr)
1713 struct nat64lsn_cfg *cfg;
1715 cfg = malloc(sizeof(struct nat64lsn_cfg), M_IPFW, M_WAITOK | M_ZERO);
1716 TAILQ_INIT(&cfg->jhead);
1719 COUNTER_ARRAY_ALLOC(cfg->base.stats.cnt, NAT64STATS, M_WAITOK);
1721 cfg->ihsize = NAT64LSN_HSIZE;
1722 cfg->ih = malloc(sizeof(void *) * cfg->ihsize, M_IPFW,
1725 cfg->pg = malloc(sizeof(void *) * numaddr * _ADDR_PG_COUNT, M_IPFW,
1728 callout_init(&cfg->periodic, CALLOUT_MPSAFE);
1729 callout_init(&cfg->jcallout, CALLOUT_MPSAFE);
1735 * Destroy all hosts callback.
1736 * Called on module unload when all activity already finished, so
1737 * can work without any locks.
1739 static NAT64NOINLINE int
1740 nat64lsn_destroy_host(struct nat64lsn_host *nh, struct nat64lsn_cfg *cfg)
1742 struct nat64lsn_portgroup *pg;
1745 for (i = nh->pg_used; i > 0; i--) {
1746 pg = PORTGROUP_BYSIDX(cfg, nh, i);
1749 cfg->pg[pg->idx] = NULL;
1750 destroy_portgroup(pg);
1759 nat64lsn_destroy_instance(struct nat64lsn_cfg *cfg)
1761 struct nat64lsn_host *nh, *tmp;
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);
1768 COUNTER_ARRAY_FREE(cfg->base.stats.cnt, NAT64STATS);
1769 free(cfg->ih, M_IPFW);
1770 free(cfg->pg, M_IPFW);