svn commit: r333403 - in head: sbin/ipfw sys/modules/ipfw_nat64 sys/netpfil/ipfw/nat64

Andrey V. Elsukov ae at FreeBSD.org
Wed May 9 11:59:26 UTC 2018


Author: ae
Date: Wed May  9 11:59:24 2018
New Revision: 333403
URL: https://svnweb.freebsd.org/changeset/base/333403

Log:
  Bring in some last changes in NAT64 implementation:
  
  o Modify ipfw(8) to be able set any prefix6 not just Well-Known,
    and also show configured prefix6;
  o relocate some definitions and macros into proper place;
  o convert nat64_debug and nat64_allow_private variables to be
    VNET-compatible;
  o add struct nat64_config that keeps generic configuration needed
    to NAT64 code;
  o add nat64_check_prefix6() function to check validness of specified
    by user IPv6 prefix according to RFC6052;
  o use nat64_check_private_ip4() and nat64_embed_ip4() functions
    instead of nat64_get_ip4() and nat64_set_ip4() macros. This allows
    to use any configured IPv6 prefixes that are allowed by RFC6052;
  o introduce NAT64_WKPFX flag, that is set when IPv6 prefix is
    Well-Known IPv6 prefix. It is used to reduce overhead to check this;
  o modify nat64lsn_cfg and nat64stl_cfg structures to use nat64_config
    structure. And respectivelly modify the rest of code;
  o remove now unused ro argument from nat64_output() function;
  o remove __FreeBSD_version ifdef, NAT64 was not merged to older versions;
  o add commented -DIPFIREWALL_NAT64_DIRECT_OUTPUT flag to module's Makefile
    as example.
  
  Obtained from:	Yandex LLC
  MFC after:	1 month
  Sponsored by:	Yandex LLC

Modified:
  head/sbin/ipfw/ipfw2.h
  head/sbin/ipfw/nat64lsn.c
  head/sbin/ipfw/nat64stl.c
  head/sys/modules/ipfw_nat64/Makefile
  head/sys/netpfil/ipfw/nat64/ip_fw_nat64.c
  head/sys/netpfil/ipfw/nat64/ip_fw_nat64.h
  head/sys/netpfil/ipfw/nat64/nat64_translate.c
  head/sys/netpfil/ipfw/nat64/nat64_translate.h
  head/sys/netpfil/ipfw/nat64/nat64lsn.c
  head/sys/netpfil/ipfw/nat64/nat64lsn.h
  head/sys/netpfil/ipfw/nat64/nat64lsn_control.c
  head/sys/netpfil/ipfw/nat64/nat64stl.c
  head/sys/netpfil/ipfw/nat64/nat64stl.h
  head/sys/netpfil/ipfw/nat64/nat64stl_control.c

Modified: head/sbin/ipfw/ipfw2.h
==============================================================================
--- head/sbin/ipfw/ipfw2.h	Wed May  9 11:47:05 2018	(r333402)
+++ head/sbin/ipfw/ipfw2.h	Wed May  9 11:59:24 2018	(r333403)
@@ -384,6 +384,7 @@ void ipfw_nat64lsn_handler(int ac, char *av[]);
 void ipfw_nat64stl_handler(int ac, char *av[]);
 void ipfw_nptv6_handler(int ac, char *av[]);
 int ipfw_check_object_name(const char *name);
+int ipfw_check_nat64prefix(const struct in6_addr *prefix, int length);
 
 #ifdef PF
 /* altq.c */

Modified: head/sbin/ipfw/nat64lsn.c
==============================================================================
--- head/sbin/ipfw/nat64lsn.c	Wed May  9 11:47:05 2018	(r333402)
+++ head/sbin/ipfw/nat64lsn.c	Wed May  9 11:59:24 2018	(r333403)
@@ -428,13 +428,17 @@ nat64lsn_create(const char *name, uint8_t set, int ac,
 			flags |= NAT64LSN_HAS_PREFIX4;
 			ac--; av++;
 			break;
-#if 0
 		case TOK_PREFIX6:
 			NEED1("IPv6 prefix required");
 			nat64lsn_parse_prefix(*av, AF_INET6, &cfg->prefix6,
 			    &cfg->plen6);
+			if (ipfw_check_nat64prefix(&cfg->prefix6,
+			    cfg->plen6) != 0)
+				errx(EX_USAGE, "Bad prefix6 %s", *av);
+
 			ac--; av++;
 			break;
+#if 0
 		case TOK_AGG_LEN:
 			NEED1("Aggregation prefix len required");
 			cfg->agg_prefix_len = nat64lsn_parse_int(*av, opt);
@@ -767,10 +771,10 @@ nat64lsn_show_cb(ipfw_nat64lsn_cfg *cfg, const char *n
 	if (co.use_set != 0 || cfg->set != 0)
 		printf("set %u ", cfg->set);
 	inet_ntop(AF_INET, &cfg->prefix4, abuf, sizeof(abuf));
-	printf("nat64lsn %s prefix4 %s/%u ", cfg->name, abuf, cfg->plen4);
-#if 0
+	printf("nat64lsn %s prefix4 %s/%u", cfg->name, abuf, cfg->plen4);
 	inet_ntop(AF_INET6, &cfg->prefix6, abuf, sizeof(abuf));
-	printf("prefix6 %s/%u", abuf, cfg->plen6);
+	printf(" prefix6 %s/%u", abuf, cfg->plen6);
+#if 0
 	printf("agg_len %u agg_count %u ", cfg->agg_prefix_len,
 	    cfg->agg_prefix_max);
 	if (cfg->min_port != NAT64LSN_PORT_MIN ||

Modified: head/sbin/ipfw/nat64stl.c
==============================================================================
--- head/sbin/ipfw/nat64stl.c	Wed May  9 11:47:05 2018	(r333402)
+++ head/sbin/ipfw/nat64stl.c	Wed May  9 11:59:24 2018	(r333403)
@@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$");
 #include <netinet6/ip_fw_nat64.h>
 #include <arpa/inet.h>
 
-static int nat64stl_check_prefix(struct in6_addr *prefix, int length);
 typedef int (nat64stl_cb_t)(ipfw_nat64stl_cfg *i, const char *name,
     uint8_t set);
 static int nat64stl_foreach(nat64stl_cb_t *f, const char *name, uint8_t set,
@@ -80,13 +79,10 @@ static struct _s_x nat64cmds[] = {
     ((a)->__u6_addr.__u6_addr32[0] == IPV6_ADDR_INT32_WKPFX &&	\
 	(a)->__u6_addr.__u6_addr32[1] == 0 &&			\
 	(a)->__u6_addr.__u6_addr32[2] == 0)
-static int
-nat64stl_check_prefix(struct in6_addr *prefix, int length)
+int
+ipfw_check_nat64prefix(const struct in6_addr *prefix, int length)
 {
 
-	if (IN6_IS_ADDR_WKPFX(prefix) && length == 96)
-		return (0);
-#if 0
 	switch (length) {
 	case 32:
 	case 40:
@@ -95,21 +91,20 @@ nat64stl_check_prefix(struct in6_addr *prefix, int len
 	case 64:
 		/* Well-known prefix has 96 prefix length */
 		if (IN6_IS_ADDR_WKPFX(prefix))
-			return (1);
+			return (EINVAL);
 		/* FALLTHROUGH */
 	case 96:
 		/* Bits 64 to 71 must be set to zero */
 		if (prefix->__u6_addr.__u6_addr8[8] != 0)
-			return (1);
+			return (EINVAL);
 		/* XXX: looks incorrect */
 		if (IN6_IS_ADDR_MULTICAST(prefix) ||
 		    IN6_IS_ADDR_UNSPECIFIED(prefix) ||
 		    IN6_IS_ADDR_LOOPBACK(prefix))
-			return (1);
+			return (EINVAL);
 		return (0);
 	}
-#endif
-	return (1);
+	return (EINVAL);
 }
 
 static struct _s_x nat64statscmds[] = {
@@ -255,7 +250,7 @@ nat64stl_create(const char *name, uint8_t set, int ac,
 				errx(EX_USAGE,
 				    "Bad prefix: %s", *av);
 			cfg->plen6 = strtol(p, NULL, 10);
-			if (nat64stl_check_prefix(&cfg->prefix6,
+			if (ipfw_check_nat64prefix(&cfg->prefix6,
 			    cfg->plen6) != 0)
 				errx(EX_USAGE,
 				    "Bad prefix length: %s", p);
@@ -439,6 +434,7 @@ nat64stl_reset_stats(const char *name, uint8_t set)
 static int
 nat64stl_show_cb(ipfw_nat64stl_cfg *cfg, const char *name, uint8_t set)
 {
+	char abuf[INET6_ADDRSTRLEN];
 
 	if (name != NULL && strcmp(cfg->name, name) != 0)
 		return (ESRCH);
@@ -448,8 +444,11 @@ nat64stl_show_cb(ipfw_nat64stl_cfg *cfg, const char *n
 
 	if (co.use_set != 0 || cfg->set != 0)
 		printf("set %u ", cfg->set);
+
 	printf("nat64stl %s table4 %s table6 %s",
 	    cfg->name, cfg->ntlv4.name, cfg->ntlv6.name);
+	inet_ntop(AF_INET6, &cfg->prefix6, abuf, sizeof(abuf));
+	printf(" prefix6 %s/%u", abuf, cfg->plen6);
 	if (cfg->flags & NAT64_LOG)
 		printf(" log");
 	printf("\n");

Modified: head/sys/modules/ipfw_nat64/Makefile
==============================================================================
--- head/sys/modules/ipfw_nat64/Makefile	Wed May  9 11:47:05 2018	(r333402)
+++ head/sys/modules/ipfw_nat64/Makefile	Wed May  9 11:59:24 2018	(r333403)
@@ -8,4 +8,6 @@ SRCS+=	nat64lsn.c nat64lsn_control.c
 SRCS+=	nat64stl.c nat64stl_control.c
 SRCS+=	opt_ipfw.h
 
+#CFLAGS+=	-DIPFIREWALL_NAT64_DIRECT_OUTPUT
+
 .include <bsd.kmod.mk>

Modified: head/sys/netpfil/ipfw/nat64/ip_fw_nat64.c
==============================================================================
--- head/sys/netpfil/ipfw/nat64/ip_fw_nat64.c	Wed May  9 11:47:05 2018	(r333402)
+++ head/sys/netpfil/ipfw/nat64/ip_fw_nat64.c	Wed May  9 11:59:24 2018	(r333403)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 2015-2016 Yandex LLC
- * Copyright (c) 2015-2016 Andrey V. Elsukov <ae at FreeBSD.org>
+ * Copyright (c) 2015-2018 Yandex LLC
+ * Copyright (c) 2015-2018 Andrey V. Elsukov <ae at FreeBSD.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -46,18 +46,17 @@ __FBSDID("$FreeBSD$");
 #include <netinet/ip_fw.h>
 
 #include <netpfil/ipfw/ip_fw_private.h>
-#include <netpfil/ipfw/nat64/ip_fw_nat64.h>
-#include <netpfil/ipfw/nat64/nat64_translate.h>
 
+#include "ip_fw_nat64.h"
 
-int nat64_debug = 0;
-SYSCTL_DECL(_net_inet_ip_fw);
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, nat64_debug, CTLFLAG_RW,
-    &nat64_debug, 0, "Debug level for NAT64 module");
+VNET_DEFINE(int, nat64_debug) = 0;
+VNET_DEFINE(int, nat64_allow_private) = 0;
 
-int nat64_allow_private = 0;
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, nat64_allow_private, CTLFLAG_RW,
-    &nat64_allow_private, 0,
+SYSCTL_DECL(_net_inet_ip_fw);
+SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, nat64_debug, CTLFLAG_VNET | CTLFLAG_RW,
+    &VNET_NAME(nat64_debug), 0, "Debug level for NAT64 module");
+SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, nat64_allow_private,
+    CTLFLAG_VNET |CTLFLAG_RW, &VNET_NAME(nat64_allow_private), 0,
     "Allow use of non-global IPv4 addresses with NAT64");
 
 static int

Modified: head/sys/netpfil/ipfw/nat64/ip_fw_nat64.h
==============================================================================
--- head/sys/netpfil/ipfw/nat64/ip_fw_nat64.h	Wed May  9 11:47:05 2018	(r333402)
+++ head/sys/netpfil/ipfw/nat64/ip_fw_nat64.h	Wed May  9 11:59:24 2018	(r333403)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 2015-2016 Yandex LLC
- * Copyright (c) 2015-2016 Andrey V. Elsukov <ae at FreeBSD.org>
+ * Copyright (c) 2015-2018 Yandex LLC
+ * Copyright (c) 2015-2018 Andrey V. Elsukov <ae at FreeBSD.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,7 @@
 #define	_IP_FW_NAT64_H_
 
 #define	DPRINTF(mask, fmt, ...)	\
-    if (nat64_debug & (mask))	\
+    if (V_nat64_debug & (mask))	\
 	printf("NAT64: %s: " fmt "\n", __func__, ## __VA_ARGS__)
 #define	DP_GENERIC	0x0001
 #define	DP_OBJ		0x0002
@@ -39,79 +39,21 @@
 #define	DP_STATE	0x0008
 #define	DP_DROPS	0x0010
 #define	DP_ALL		0xFFFF
-extern int nat64_debug;
 
+VNET_DECLARE(int, nat64_debug);
+VNET_DECLARE(int, nat64_allow_private);
+#define	V_nat64_debug		VNET(nat64_debug)
+#define	V_nat64_allow_private	VNET(nat64_allow_private)
+
 #if 0
 #define	NAT64NOINLINE	__noinline
 #else
 #define	NAT64NOINLINE
 #endif
 
-int nat64stl_init(struct ip_fw_chain *ch, int first);
-void nat64stl_uninit(struct ip_fw_chain *ch, int last);
-int nat64lsn_init(struct ip_fw_chain *ch, int first);
-void nat64lsn_uninit(struct ip_fw_chain *ch, int last);
+int	nat64stl_init(struct ip_fw_chain *ch, int first);
+void	nat64stl_uninit(struct ip_fw_chain *ch, int last);
+int	nat64lsn_init(struct ip_fw_chain *ch, int first);
+void	nat64lsn_uninit(struct ip_fw_chain *ch, int last);
 
-struct ip_fw_nat64_stats {
-	counter_u64_t	opcnt64;	/* 6to4 of packets translated */
-	counter_u64_t	opcnt46;	/* 4to6 of packets translated */
-	counter_u64_t	ofrags;		/* number of fragments generated */
-	counter_u64_t	ifrags;		/* number of fragments received */
-	counter_u64_t	oerrors;	/* number of output errors */
-	counter_u64_t	noroute4;
-	counter_u64_t	noroute6;
-	counter_u64_t	nomatch4;	/* No addr/port match */
-	counter_u64_t	noproto;	/* Protocol not supported */
-	counter_u64_t	nomem;		/* mbufs allocation failed */
-	counter_u64_t	dropped;	/* number of packets silently
-					 * dropped due to some errors/
-					 * unsupported/etc.
-					 */
-
-	counter_u64_t	jrequests;	/* number of jobs requests queued */
-	counter_u64_t	jcalls;		/* number of jobs handler calls */
-	counter_u64_t	jhostsreq;	/* number of hosts requests */
-	counter_u64_t	jportreq;
-	counter_u64_t	jhostfails;
-	counter_u64_t	jportfails;
-	counter_u64_t	jmaxlen;
-	counter_u64_t	jnomem;
-	counter_u64_t	jreinjected;
-
-	counter_u64_t	screated;
-	counter_u64_t	sdeleted;
-	counter_u64_t	spgcreated;
-	counter_u64_t	spgdeleted;
-};
-
-#define	IPFW_NAT64_VERSION	1
-#define	NAT64STATS	(sizeof(struct ip_fw_nat64_stats) / sizeof(uint64_t))
-typedef struct _nat64_stats_block {
-	counter_u64_t		stats[NAT64STATS];
-} nat64_stats_block;
-#define	NAT64STAT_ADD(s, f, v)		\
-    counter_u64_add((s)->stats[		\
-	offsetof(struct ip_fw_nat64_stats, f) / sizeof(uint64_t)], (v))
-#define	NAT64STAT_INC(s, f)	NAT64STAT_ADD(s, f, 1)
-#define	NAT64STAT_FETCH(s, f)		\
-    counter_u64_fetch((s)->stats[	\
-	offsetof(struct ip_fw_nat64_stats, f) / sizeof(uint64_t)])
-
-#define	L3HDR(_ip, _t)	((_t)((u_int32_t *)(_ip) + (_ip)->ip_hl))
-#define	TCP(p)		((struct tcphdr *)(p))
-#define	UDP(p)		((struct udphdr *)(p))
-#define	ICMP(p)		((struct icmphdr *)(p))
-#define	ICMP6(p)	((struct icmp6_hdr *)(p))
-
-#define	NAT64SKIP	0
-#define	NAT64RETURN	1
-#define	NAT64MFREE	-1
-
-/* Well-known prefix 64:ff9b::/96 */
-#define	IPV6_ADDR_INT32_WKPFX	htonl(0x64ff9b)
-#define	IN6_IS_ADDR_WKPFX(a)	\
-    ((a)->s6_addr32[0] == IPV6_ADDR_INT32_WKPFX && \
-	(a)->s6_addr32[1] == 0 && (a)->s6_addr32[2] == 0)
-
-#endif
-
+#endif /* _IP_FW_NAT64_H_ */

Modified: head/sys/netpfil/ipfw/nat64/nat64_translate.c
==============================================================================
--- head/sys/netpfil/ipfw/nat64/nat64_translate.c	Wed May  9 11:47:05 2018	(r333402)
+++ head/sys/netpfil/ipfw/nat64/nat64_translate.c	Wed May  9 11:59:24 2018	(r333403)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 2015-2016 Yandex LLC
- * Copyright (c) 2015-2016 Andrey V. Elsukov <ae at FreeBSD.org>
+ * Copyright (c) 2015-2018 Yandex LLC
+ * Copyright (c) 2015-2018 Andrey V. Elsukov <ae at FreeBSD.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -66,10 +66,11 @@ __FBSDID("$FreeBSD$");
 
 #include <netpfil/pf/pf.h>
 #include <netpfil/ipfw/ip_fw_private.h>
-#include <netpfil/ipfw/nat64/ip_fw_nat64.h>
-#include <netpfil/ipfw/nat64/nat64_translate.h>
 #include <machine/in_cksum.h>
 
+#include "ip_fw_nat64.h"
+#include "nat64_translate.h"
+
 static void
 nat64_log(struct pfloghdr *logdata, struct mbuf *m, sa_family_t family)
 {
@@ -86,22 +87,21 @@ static NAT64NOINLINE int nat64_find_route6(struct nhop
     struct sockaddr_in6 *, struct mbuf *);
 
 static NAT64NOINLINE int
-nat64_output(struct ifnet *ifp, struct mbuf *m,
-    struct sockaddr *dst, struct route *ro, nat64_stats_block *stats,
-    void *logdata)
+nat64_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
+    struct nat64_counters *stats, void *logdata)
 {
 	int error;
 
 	if (logdata != NULL)
 		nat64_log(logdata, m, dst->sa_family);
-	error = (*ifp->if_output)(ifp, m, dst, ro);
+	error = (*ifp->if_output)(ifp, m, dst, NULL);
 	if (error != 0)
 		NAT64STAT_INC(stats, oerrors);
 	return (error);
 }
 
 static NAT64NOINLINE int
-nat64_output_one(struct mbuf *m, nat64_stats_block *stats, void *logdata)
+nat64_output_one(struct mbuf *m, struct nat64_counters *stats, void *logdata)
 {
 	struct nhop6_basic nh6;
 	struct nhop4_basic nh4;
@@ -155,9 +155,8 @@ nat64_output_one(struct mbuf *m, nat64_stats_block *st
 }
 #else /* !IPFIREWALL_NAT64_DIRECT_OUTPUT */
 static NAT64NOINLINE int
-nat64_output(struct ifnet *ifp, struct mbuf *m,
-    struct sockaddr *dst, struct route *ro, nat64_stats_block *stats,
-    void *logdata)
+nat64_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
+    struct nat64_counters *stats, void *logdata)
 {
 	struct ip *ip4;
 	int ret, af;
@@ -187,50 +186,103 @@ nat64_output(struct ifnet *ifp, struct mbuf *m,
 }
 
 static NAT64NOINLINE int
-nat64_output_one(struct mbuf *m, nat64_stats_block *stats, void *logdata)
+nat64_output_one(struct mbuf *m, struct nat64_counters *stats, void *logdata)
 {
 
-	return (nat64_output(NULL, m, NULL, NULL, stats, logdata));
+	return (nat64_output(NULL, m, NULL, stats, logdata));
 }
 #endif /* !IPFIREWALL_NAT64_DIRECT_OUTPUT */
 
+/*
+ * Check the given IPv6 prefix and length according to RFC6052:
+ *   The prefixes can only have one of the following lengths:
+ *   32, 40, 48, 56, 64, or 96 (The Well-Known Prefix is 96 bits long).
+ * Returns zero on success, otherwise EINVAL.
+ */
+int
+nat64_check_prefix6(const struct in6_addr *prefix, int length)
+{
 
-#if 0
-void print_ipv6_header(struct ip6_hdr *ip6, char *buf, size_t bufsize);
+	switch (length) {
+	case 32:
+	case 40:
+	case 48:
+	case 56:
+	case 64:
+		/* Well-known prefix has 96 prefix length */
+		if (IN6_IS_ADDR_WKPFX(prefix))
+			return (EINVAL);
+		/* FALLTHROUGH */
+	case 96:
+		/* Bits 64 to 71 must be set to zero */
+		if (prefix->__u6_addr.__u6_addr8[8] != 0)
+			return (EINVAL);
+		/* Some extra checks */
+		if (IN6_IS_ADDR_MULTICAST(prefix) ||
+		    IN6_IS_ADDR_UNSPECIFIED(prefix) ||
+		    IN6_IS_ADDR_LOOPBACK(prefix))
+			return (EINVAL);
+		return (0);
+	}
+	return (EINVAL);
+}
 
-void
-print_ipv6_header(struct ip6_hdr *ip6, char *buf, size_t bufsize)
+int
+nat64_check_private_ip4(const struct nat64_config *cfg, in_addr_t ia)
 {
-	char sbuf[INET6_ADDRSTRLEN], dbuf[INET6_ADDRSTRLEN];
 
-	inet_ntop(AF_INET6, &ip6->ip6_src, sbuf, sizeof(sbuf));
-	inet_ntop(AF_INET6, &ip6->ip6_dst, dbuf, sizeof(dbuf));
-	snprintf(buf, bufsize, "%s -> %s %d", sbuf, dbuf, ip6->ip6_nxt);
+	if (V_nat64_allow_private)
+		return (0);
+
+	/* WKPFX must not be used to represent non-global IPv4 addresses */
+	if (cfg->flags & NAT64_WKPFX) {
+		/* IN_PRIVATE */
+		if ((ia & htonl(0xff000000)) == htonl(0x0a000000) ||
+		    (ia & htonl(0xfff00000)) == htonl(0xac100000) ||
+		    (ia & htonl(0xffff0000)) == htonl(0xc0a80000))
+			return (1);
+		/*
+		 * RFC 5735:
+		 *  192.0.0.0/24 - reserved for IETF protocol assignments
+		 *  192.88.99.0/24 - for use as 6to4 relay anycast addresses
+		 *  198.18.0.0/15 - for use in benchmark tests
+		 *  192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24 - for use
+		 *   in documentation and example code
+		 */
+		if ((ia & htonl(0xffffff00)) == htonl(0xc0000000) ||
+		    (ia & htonl(0xffffff00)) == htonl(0xc0586300) ||
+		    (ia & htonl(0xfffffe00)) == htonl(0xc6120000) ||
+		    (ia & htonl(0xffffff00)) == htonl(0xc0000200) ||
+		    (ia & htonl(0xfffffe00)) == htonl(0xc6336400) ||
+		    (ia & htonl(0xffffff00)) == htonl(0xcb007100))
+			return (1);
+	}
+	return (0);
 }
 
-
-static NAT64NOINLINE int
-nat64_embed_ip4(struct nat64_cfg *cfg, in_addr_t ia, struct in6_addr *ip6)
+void
+nat64_embed_ip4(const struct nat64_config *cfg, in_addr_t ia,
+    struct in6_addr *ip6)
 {
 
-	/* assume the prefix is properly filled with zeros */
-	bcopy(&cfg->prefix, ip6, sizeof(*ip6));
-	switch (cfg->plen) {
+	/* assume the prefix6 is properly filled with zeros */
+	bcopy(&cfg->prefix6, ip6, sizeof(*ip6));
+	switch (cfg->plen6) {
 	case 32:
 	case 96:
-		ip6->s6_addr32[cfg->plen / 32] = ia;
+		ip6->s6_addr32[cfg->plen6 / 32] = ia;
 		break;
 	case 40:
 	case 48:
 	case 56:
 #if BYTE_ORDER == BIG_ENDIAN
-		ip6->s6_addr32[1] = cfg->prefix.s6_addr32[1] |
-		    (ia >> (cfg->plen % 32));
-		ip6->s6_addr32[2] = ia << (24 - cfg->plen % 32);
+		ip6->s6_addr32[1] = cfg->prefix6.s6_addr32[1] |
+		    (ia >> (cfg->plen6 % 32));
+		ip6->s6_addr32[2] = ia << (24 - cfg->plen6 % 32);
 #elif BYTE_ORDER == LITTLE_ENDIAN
-		ip6->s6_addr32[1] = cfg->prefix.s6_addr32[1] |
-		    (ia << (cfg->plen % 32));
-		ip6->s6_addr32[2] = ia >> (24 - cfg->plen % 32);
+		ip6->s6_addr32[1] = cfg->prefix6.s6_addr32[1] |
+		    (ia << (cfg->plen6 % 32));
+		ip6->s6_addr32[2] = ia >> (24 - cfg->plen6 % 32);
 #endif
 		break;
 	case 64:
@@ -243,14 +295,13 @@ nat64_embed_ip4(struct nat64_cfg *cfg, in_addr_t ia, s
 #endif
 		break;
 	default:
-		return (0);
+		panic("Wrong plen6");
 	};
 	ip6->s6_addr8[8] = 0;
-	return (1);
 }
 
-static NAT64NOINLINE in_addr_t
-nat64_extract_ip4(struct in6_addr *ip6, int plen)
+in_addr_t
+nat64_extract_ip4(const struct nat64_config *cfg, const struct in6_addr *ip6)
 {
 	in_addr_t ia;
 
@@ -261,7 +312,7 @@ nat64_extract_ip4(struct in6_addr *ip6, int plen)
 	 * The suffix bits are reserved for future extensions and SHOULD
 	 * be set to zero.
 	 */
-	switch (plen) {
+	switch (cfg->plen6) {
 	case 32:
 		if (ip6->s6_addr32[3] != 0 || ip6->s6_addr32[2] != 0)
 			goto badip6;
@@ -285,20 +336,20 @@ nat64_extract_ip4(struct in6_addr *ip6, int plen)
 		    (ip6->s6_addr32[3] & htonl(0x00ffffff)) != 0)
 			goto badip6;
 	};
-	switch (plen) {
+	switch (cfg->plen6) {
 	case 32:
 	case 96:
-		ia = ip6->s6_addr32[plen / 32];
+		ia = ip6->s6_addr32[cfg->plen6 / 32];
 		break;
 	case 40:
 	case 48:
 	case 56:
 #if BYTE_ORDER == BIG_ENDIAN
-		ia = (ip6->s6_addr32[1] << (plen % 32)) |
-		    (ip6->s6_addr32[2] >> (24 - plen % 32));
+		ia = (ip6->s6_addr32[1] << (cfg->plen6 % 32)) |
+		    (ip6->s6_addr32[2] >> (24 - cfg->plen6 % 32));
 #elif BYTE_ORDER == LITTLE_ENDIAN
-		ia = (ip6->s6_addr32[1] >> (plen % 32)) |
-		    (ip6->s6_addr32[2] << (24 - plen % 32));
+		ia = (ip6->s6_addr32[1] >> (cfg->plen6 % 32)) |
+		    (ip6->s6_addr32[2] << (24 - cfg->plen6 % 32));
 #endif
 		break;
 	case 64:
@@ -312,18 +363,18 @@ nat64_extract_ip4(struct in6_addr *ip6, int plen)
 		return (0);
 	};
 	if (nat64_check_ip4(ia) != 0 ||
-	    nat64_check_private_ip4(ia) != 0)
+	    nat64_check_private_ip4(cfg, ia) != 0)
 		goto badip4;
 
 	return (ia);
 badip4:
-	DPRINTF(DP_GENERIC, "invalid destination address: %08x", ia);
+	DPRINTF(DP_GENERIC | DP_DROPS,
+	    "invalid destination address: %08x", ia);
 	return (0);
 badip6:
-	DPRINTF(DP_GENERIC, "invalid IPv4-embedded IPv6 address");
+	DPRINTF(DP_GENERIC | DP_DROPS, "invalid IPv4-embedded IPv6 address");
 	return (0);
 }
-#endif
 
 /*
  * According to RFC 1624 the equation for incremental checksum update is:
@@ -363,9 +414,6 @@ nat64_cksum_convert(struct ip6_hdr *ip6, struct ip *ip
 	return (sum);
 }
 
-#if __FreeBSD_version < 1100000
-#define	ip_fillid(ip)		(ip)->ip_id = ip_newid()
-#endif
 static NAT64NOINLINE void
 nat64_init_ip4hdr(const struct ip6_hdr *ip6, const struct ip6_frag *frag,
     uint16_t plen, uint8_t proto, struct ip *ip)
@@ -397,8 +445,9 @@ nat64_init_ip4hdr(const struct ip6_hdr *ip6, const str
 
 #define	FRAGSZ(mtu) ((mtu) - sizeof(struct ip6_hdr) - sizeof(struct ip6_frag))
 static NAT64NOINLINE int
-nat64_fragment6(nat64_stats_block *stats, struct ip6_hdr *ip6, struct mbufq *mq,
-    struct mbuf *m, uint32_t mtu, uint16_t ip_id, uint16_t ip_off)
+nat64_fragment6(struct nat64_counters *stats, struct ip6_hdr *ip6,
+    struct mbufq *mq, struct mbuf *m, uint32_t mtu, uint16_t ip_id,
+    uint16_t ip_off)
 {
 	struct ip6_frag ip6f;
 	struct mbuf *n;
@@ -510,7 +559,7 @@ nat64_find_route6(struct nhop6_basic *pnh, struct sock
 #define	NAT64_ICMP6_PLEN	64
 static NAT64NOINLINE void
 nat64_icmp6_reflect(struct mbuf *m, uint8_t type, uint8_t code, uint32_t mtu,
-    nat64_stats_block *stats, void *logdata)
+    struct nat64_counters *stats, void *logdata)
 {
 	struct icmp6_hdr *icmp6;
 	struct ip6_hdr *ip6, *oip6;
@@ -625,7 +674,7 @@ nat64_find_route4(struct nhop4_basic *pnh, struct sock
 #define	NAT64_ICMP_PLEN	64
 static NAT64NOINLINE void
 nat64_icmp_reflect(struct mbuf *m, uint8_t type,
-    uint8_t code, uint16_t mtu, nat64_stats_block *stats, void *logdata)
+    uint8_t code, uint16_t mtu, struct nat64_counters *stats, void *logdata)
 {
 	struct icmp *icmp;
 	struct ip *ip, *oip;
@@ -734,7 +783,7 @@ nat64_icmp_handle_echo(struct ip6_hdr *ip6, struct icm
 
 static NAT64NOINLINE struct mbuf *
 nat64_icmp_translate(struct mbuf *m, struct ip6_hdr *ip6, uint16_t icmpid,
-    int offset, nat64_stats_block *stats)
+    int offset, struct nat64_config *cfg)
 {
 	struct ip ip;
 	struct icmp *icmp;
@@ -749,7 +798,7 @@ nat64_icmp_translate(struct mbuf *m, struct ip6_hdr *i
 	if (m->m_len < offset + ICMP_MINLEN)
 		m = m_pullup(m, offset + ICMP_MINLEN);
 	if (m == NULL) {
-		NAT64STAT_INC(stats, nomem);
+		NAT64STAT_INC(&cfg->stats, nomem);
 		return (m);
 	}
 	mtu = 0;
@@ -889,8 +938,8 @@ nat64_icmp_translate(struct mbuf *m, struct ip6_hdr *i
 	hlen += ip.ip_hl << 2; /* Skip inner IP header */
 	if (nat64_check_ip4(ip.ip_src.s_addr) != 0 ||
 	    nat64_check_ip4(ip.ip_dst.s_addr) != 0 ||
-	    nat64_check_private_ip4(ip.ip_src.s_addr) != 0 ||
-	    nat64_check_private_ip4(ip.ip_dst.s_addr) != 0) {
+	    nat64_check_private_ip4(cfg, ip.ip_src.s_addr) != 0 ||
+	    nat64_check_private_ip4(cfg, ip.ip_dst.s_addr) != 0) {
 		DPRINTF(DP_DROPS, "IP addresses checks failed %04x -> %04x",
 		    ntohl(ip.ip_src.s_addr), ntohl(ip.ip_dst.s_addr));
 		goto freeit;
@@ -925,7 +974,7 @@ nat64_icmp_translate(struct mbuf *m, struct ip6_hdr *i
 	plen = sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr) + len;
 	n = m_get2(offset + plen + max_hdr, M_NOWAIT, MT_HEADER, M_PKTHDR);
 	if (n == NULL) {
-		NAT64STAT_INC(stats, nomem);
+		NAT64STAT_INC(&cfg->stats, nomem);
 		m_freem(m);
 		return (NULL);
 	}
@@ -939,7 +988,7 @@ nat64_icmp_translate(struct mbuf *m, struct ip6_hdr *i
 	eip6->ip6_src = ip6->ip6_dst;
 	/* Use the fact that we have single /96 prefix for IPv4 map */
 	eip6->ip6_dst = ip6->ip6_src;
-	nat64_set_ip4(&eip6->ip6_dst, ip.ip_dst.s_addr);
+	nat64_embed_ip4(cfg, ip.ip_dst.s_addr, &eip6->ip6_dst);
 
 	eip6->ip6_flow = htonl(ip.ip_tos << 20);
 	eip6->ip6_vfc |= IPV6_VERSION;
@@ -1009,7 +1058,7 @@ nat64_icmp_translate(struct mbuf *m, struct ip6_hdr *i
 	return (n);
 freeit:
 	m_freem(m);
-	NAT64STAT_INC(stats, dropped);
+	NAT64STAT_INC(&cfg->stats, dropped);
 	return (NULL);
 }
 
@@ -1057,7 +1106,7 @@ nat64_getlasthdr(struct mbuf *m, int *offset)
 
 int
 nat64_do_handle_ip4(struct mbuf *m, struct in6_addr *saddr,
-    struct in6_addr *daddr, uint16_t lport, nat64_stats_block *stats,
+    struct in6_addr *daddr, uint16_t lport, struct nat64_config *cfg,
     void *logdata)
 {
 	struct nhop6_basic nh;
@@ -1074,7 +1123,7 @@ nat64_do_handle_ip4(struct mbuf *m, struct in6_addr *s
 
 	if (ip->ip_ttl <= IPTTLDEC) {
 		nat64_icmp_reflect(m, ICMP_TIMXCEED,
-		    ICMP_TIMXCEED_INTRANS, 0, stats, logdata);
+		    ICMP_TIMXCEED_INTRANS, 0, &cfg->stats, logdata);
 		return (NAT64RETURN);
 	}
 
@@ -1092,27 +1141,27 @@ nat64_do_handle_ip4(struct mbuf *m, struct in6_addr *s
 	/* Fragment length must be multiple of 8 octets */
 	if ((ip->ip_off & htons(IP_MF)) != 0 && (plen & 0x7) != 0) {
 		nat64_icmp_reflect(m, ICMP_PARAMPROB,
-		    ICMP_PARAMPROB_LENGTH, 0, stats, logdata);
+		    ICMP_PARAMPROB_LENGTH, 0, &cfg->stats, logdata);
 		return (NAT64RETURN);
 	}
 	/* Fragmented ICMP is unsupported */
 	if (proto == IPPROTO_ICMP && ip_off != 0) {
 		DPRINTF(DP_DROPS, "dropped due to fragmented ICMP");
-		NAT64STAT_INC(stats, dropped);
+		NAT64STAT_INC(&cfg->stats, dropped);
 		return (NAT64MFREE);
 	}
 
 	dst.sin6_addr = ip6.ip6_dst;
 	if (nat64_find_route6(&nh, &dst, m) != 0) {
-		NAT64STAT_INC(stats, noroute6);
+		NAT64STAT_INC(&cfg->stats, noroute6);
 		nat64_icmp_reflect(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0,
-		    stats, logdata);
+		    &cfg->stats, logdata);
 		return (NAT64RETURN);
 	}
 	if (nh.nh_mtu < plen + sizeof(ip6) &&
 	    (ip->ip_off & htons(IP_DF)) != 0) {
 		nat64_icmp_reflect(m, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG,
-		    FRAGSZ(nh.nh_mtu) + sizeof(struct ip), stats, logdata);
+		    FRAGSZ(nh.nh_mtu) + sizeof(struct ip), &cfg->stats, logdata);
 		return (NAT64RETURN);
 	}
 
@@ -1147,19 +1196,19 @@ nat64_do_handle_ip4(struct mbuf *m, struct in6_addr *s
 		*csum = cksum_add(*csum, ~nat64_cksum_convert(&ip6, ip));
 		break;
 	case IPPROTO_ICMP:
-		m = nat64_icmp_translate(m, &ip6, lport, hlen, stats);
+		m = nat64_icmp_translate(m, &ip6, lport, hlen, cfg);
 		if (m == NULL)	/* stats already accounted */
 			return (NAT64RETURN);
 	}
 
 	m_adj(m, hlen);
 	mbufq_init(&mq, 255);
-	nat64_fragment6(stats, &ip6, &mq, m, nh.nh_mtu, ip_id, ip_off);
+	nat64_fragment6(&cfg->stats, &ip6, &mq, m, nh.nh_mtu, ip_id, ip_off);
 	while ((m = mbufq_dequeue(&mq)) != NULL) {
 		if (nat64_output(nh.nh_ifp, m, (struct sockaddr *)&dst,
-		    NULL, stats, logdata) != 0)
+		    &cfg->stats, logdata) != 0)
 			break;
-		NAT64STAT_INC(stats, opcnt46);
+		NAT64STAT_INC(&cfg->stats, opcnt46);
 	}
 	mbufq_drain(&mq);
 	return (NAT64RETURN);
@@ -1167,7 +1216,7 @@ nat64_do_handle_ip4(struct mbuf *m, struct in6_addr *s
 
 int
 nat64_handle_icmp6(struct mbuf *m, int hlen, uint32_t aaddr, uint16_t aport,
-    nat64_stats_block *stats, void *logdata)
+    struct nat64_config *cfg, void *logdata)
 {
 	struct ip ip;
 	struct icmp6_hdr *icmp6;
@@ -1187,7 +1236,7 @@ nat64_handle_icmp6(struct mbuf *m, int hlen, uint32_t 
 		if (proto != IPPROTO_ICMPV6) {
 			DPRINTF(DP_DROPS,
 			    "dropped due to mbuf isn't contigious");
-			NAT64STAT_INC(stats, dropped);
+			NAT64STAT_INC(&cfg->stats, dropped);
 			return (NAT64MFREE);
 		}
 	}
@@ -1217,7 +1266,7 @@ nat64_handle_icmp6(struct mbuf *m, int hlen, uint32_t 
 			DPRINTF(DP_DROPS, "Unsupported ICMPv6 type %d,"
 			    " code %d", icmp6->icmp6_type,
 			    icmp6->icmp6_code);
-			NAT64STAT_INC(stats, dropped);
+			NAT64STAT_INC(&cfg->stats, dropped);
 			return (NAT64MFREE);
 		}
 		break;
@@ -1229,7 +1278,7 @@ nat64_handle_icmp6(struct mbuf *m, int hlen, uint32_t 
 			DPRINTF(DP_DROPS, "Wrong MTU %d in ICMPv6 type %d,"
 			    " code %d", mtu, icmp6->icmp6_type,
 			    icmp6->icmp6_code);
-			NAT64STAT_INC(stats, dropped);
+			NAT64STAT_INC(&cfg->stats, dropped);
 			return (NAT64MFREE);
 		}
 		/*
@@ -1274,7 +1323,7 @@ nat64_handle_icmp6(struct mbuf *m, int hlen, uint32_t 
 				DPRINTF(DP_DROPS, "Unsupported ICMPv6 type %d,"
 				    " code %d, pptr %d", icmp6->icmp6_type,
 				    icmp6->icmp6_code, mtu);
-				NAT64STAT_INC(stats, dropped);
+				NAT64STAT_INC(&cfg->stats, dropped);
 				return (NAT64MFREE);
 			}
 		case ICMP6_PARAMPROB_NEXTHEADER:
@@ -1285,20 +1334,20 @@ nat64_handle_icmp6(struct mbuf *m, int hlen, uint32_t 
 			DPRINTF(DP_DROPS, "Unsupported ICMPv6 type %d,"
 			    " code %d, pptr %d", icmp6->icmp6_type,
 			    icmp6->icmp6_code, ntohl(icmp6->icmp6_pptr));
-			NAT64STAT_INC(stats, dropped);
+			NAT64STAT_INC(&cfg->stats, dropped);
 			return (NAT64MFREE);
 		}
 		break;
 	default:
 		DPRINTF(DP_DROPS, "Unsupported ICMPv6 type %d, code %d",
 		    icmp6->icmp6_type, icmp6->icmp6_code);
-		NAT64STAT_INC(stats, dropped);
+		NAT64STAT_INC(&cfg->stats, dropped);
 		return (NAT64MFREE);
 	}
 
 	hlen += sizeof(struct icmp6_hdr);
 	if (m->m_pkthdr.len < hlen + sizeof(struct ip6_hdr) + ICMP_MINLEN) {
-		NAT64STAT_INC(stats, dropped);
+		NAT64STAT_INC(&cfg->stats, dropped);
 		DPRINTF(DP_DROPS, "Message is too short %d",
 		    m->m_pkthdr.len);
 		return (NAT64MFREE);
@@ -1325,7 +1374,7 @@ nat64_handle_icmp6(struct mbuf *m, int hlen, uint32_t 
 	if (m->m_len < hlen + sizeof(struct ip6_hdr) + ICMP_MINLEN)
 		m = m_pullup(m, hlen + sizeof(struct ip6_hdr) + ICMP_MINLEN);
 	if (m == NULL) {
-		NAT64STAT_INC(stats, nomem);
+		NAT64STAT_INC(&cfg->stats, nomem);
 		return (NAT64RETURN);
 	}
 	ip6 = mtod(m, struct ip6_hdr *);
@@ -1364,7 +1413,7 @@ nat64_handle_icmp6(struct mbuf *m, int hlen, uint32_t 
 
 	/* Now we need to make a fake IPv4 packet to generate ICMP message */
 	ip.ip_dst.s_addr = aaddr;
-	ip.ip_src.s_addr = nat64_get_ip4(&ip6i->ip6_src);
+	ip.ip_src.s_addr = nat64_extract_ip4(cfg, &ip6i->ip6_src);
 	/* XXX: Make fake ulp header */
 #ifdef IPFIREWALL_NAT64_DIRECT_OUTPUT
 	ip6i->ip6_hlim += IPV6_HLIMDEC; /* init_ip4hdr will decrement it */
@@ -1372,7 +1421,8 @@ nat64_handle_icmp6(struct mbuf *m, int hlen, uint32_t 
 	nat64_init_ip4hdr(ip6i, ip6f, plen, proto, &ip);
 	m_adj(m, hlen - sizeof(struct ip));
 	bcopy(&ip, mtod(m, void *), sizeof(ip));
-	nat64_icmp_reflect(m, type, code, (uint16_t)mtu, stats, logdata);
+	nat64_icmp_reflect(m, type, code, (uint16_t)mtu, &cfg->stats,
+	    logdata);
 	return (NAT64RETURN);
 fail:
 	/*
@@ -1380,13 +1430,13 @@ fail:
 	 * changed with m_pullup().
 	 */
 	m_freem(m);
-	NAT64STAT_INC(stats, dropped);
+	NAT64STAT_INC(&cfg->stats, dropped);
 	return (NAT64RETURN);
 }
 
 int
 nat64_do_handle_ip6(struct mbuf *m, uint32_t aaddr, uint16_t aport,
-    nat64_stats_block *stats, void *logdata)
+    struct nat64_config *cfg, void *logdata)
 {
 	struct ip ip;
 	struct nhop4_basic nh;
@@ -1411,21 +1461,21 @@ nat64_do_handle_ip6(struct mbuf *m, uint32_t aaddr, ui
 	/* Starting from this point we must not return zero */
 	ip.ip_src.s_addr = aaddr;
 	if (nat64_check_ip4(ip.ip_src.s_addr) != 0) {
-		DPRINTF(DP_GENERIC, "invalid source address: %08x",
+		DPRINTF(DP_GENERIC | DP_DROPS, "invalid source address: %08x",
 		    ip.ip_src.s_addr);
-		/* XXX: stats? */
+		NAT64STAT_INC(&cfg->stats, dropped);
 		return (NAT64MFREE);
 	}
 
-	ip.ip_dst.s_addr = nat64_get_ip4(&ip6->ip6_dst);
+	ip.ip_dst.s_addr = nat64_extract_ip4(cfg, &ip6->ip6_dst);
 	if (ip.ip_dst.s_addr == 0) {
-		/* XXX: stats? */
+		NAT64STAT_INC(&cfg->stats, dropped);
 		return (NAT64MFREE);
 	}
 
 	if (ip6->ip6_hlim <= IPV6_HLIMDEC) {
 		nat64_icmp6_reflect(m, ICMP6_TIME_EXCEEDED,
-		    ICMP6_TIME_EXCEED_TRANSIT, 0, stats, logdata);
+		    ICMP6_TIME_EXCEED_TRANSIT, 0, &cfg->stats, logdata);
 		return (NAT64RETURN);
 	}
 
@@ -1434,7 +1484,7 @@ nat64_do_handle_ip6(struct mbuf *m, uint32_t aaddr, ui
 	proto = nat64_getlasthdr(m, &hlen);
 	if (proto < 0) {
 		DPRINTF(DP_DROPS, "dropped due to mbuf isn't contigious");
-		NAT64STAT_INC(stats, dropped);
+		NAT64STAT_INC(&cfg->stats, dropped);
 		return (NAT64MFREE);
 	}
 	frag = NULL;
@@ -1443,7 +1493,7 @@ nat64_do_handle_ip6(struct mbuf *m, uint32_t aaddr, ui
 		if (m->m_len < hlen + sizeof(*frag)) {
 			DPRINTF(DP_DROPS,
 			    "dropped due to mbuf isn't contigious");
-			NAT64STAT_INC(stats, dropped);
+			NAT64STAT_INC(&cfg->stats, dropped);
 			return (NAT64MFREE);
 		}
 		frag = mtodo(m, hlen);
@@ -1452,7 +1502,7 @@ nat64_do_handle_ip6(struct mbuf *m, uint32_t aaddr, ui
 		/* Fragmented ICMPv6 is unsupported */
 		if (proto == IPPROTO_ICMPV6) {
 			DPRINTF(DP_DROPS, "dropped due to fragmented ICMPv6");
-			NAT64STAT_INC(stats, dropped);
+			NAT64STAT_INC(&cfg->stats, dropped);
 			return (NAT64MFREE);
 		}
 		/* Fragment length must be multiple of 8 octets */
@@ -1460,7 +1510,7 @@ nat64_do_handle_ip6(struct mbuf *m, uint32_t aaddr, ui
 		    ((plen + sizeof(struct ip6_hdr) - hlen) & 0x7) != 0) {
 			nat64_icmp6_reflect(m, ICMP6_PARAM_PROB,
 			    ICMP6_PARAMPROB_HEADER,
-			    offsetof(struct ip6_hdr, ip6_plen), stats,
+			    offsetof(struct ip6_hdr, ip6_plen), &cfg->stats,
 			    logdata);
 			return (NAT64RETURN);
 		}
@@ -1469,7 +1519,7 @@ nat64_do_handle_ip6(struct mbuf *m, uint32_t aaddr, ui
 	if (plen < 0 || m->m_pkthdr.len < plen + hlen) {
 		DPRINTF(DP_DROPS, "plen %d, pkthdr.len %d, hlen %d",
 		    plen, m->m_pkthdr.len, hlen);
-		NAT64STAT_INC(stats, dropped);
+		NAT64STAT_INC(&cfg->stats, dropped);
 		return (NAT64MFREE);
 	}
 
@@ -1479,18 +1529,18 @@ nat64_do_handle_ip6(struct mbuf *m, uint32_t aaddr, ui
 		if (icmp6->icmp6_type != ICMP6_ECHO_REQUEST &&
 		    icmp6->icmp6_type != ICMP6_ECHO_REPLY)
 			return (nat64_handle_icmp6(m, hlen, aaddr, aport,
-			    stats, logdata));
+			    cfg, logdata));
 	}
 	dst.sin_addr.s_addr = ip.ip_dst.s_addr;
 	if (nat64_find_route4(&nh, &dst, m) != 0) {
-		NAT64STAT_INC(stats, noroute4);
+		NAT64STAT_INC(&cfg->stats, noroute4);
 		nat64_icmp6_reflect(m, ICMP6_DST_UNREACH,
-		    ICMP6_DST_UNREACH_NOROUTE, 0, stats, logdata);
+		    ICMP6_DST_UNREACH_NOROUTE, 0, &cfg->stats, logdata);
 		return (NAT64RETURN);
 	}
 	if (nh.nh_mtu < plen + sizeof(ip)) {
 		nat64_icmp6_reflect(m, ICMP6_PACKET_TOO_BIG, 0, nh.nh_mtu,
-		    stats, logdata);
+		    &cfg->stats, logdata);
 		return (NAT64RETURN);
 	}
 	nat64_init_ip4hdr(ip6, frag, plen, proto, &ip);
@@ -1537,9 +1587,9 @@ nat64_do_handle_ip6(struct mbuf *m, uint32_t aaddr, ui
 
 	m_adj(m, hlen - sizeof(ip));
 	bcopy(&ip, mtod(m, void *), sizeof(ip));
-	if (nat64_output(nh.nh_ifp, m, (struct sockaddr *)&dst, NULL,
-	    stats, logdata) == 0)
-		NAT64STAT_INC(stats, opcnt64);
+	if (nat64_output(nh.nh_ifp, m, (struct sockaddr *)&dst,
+	    &cfg->stats, logdata) == 0)
+		NAT64STAT_INC(&cfg->stats, opcnt64);
 	return (NAT64RETURN);
 }
 

Modified: head/sys/netpfil/ipfw/nat64/nat64_translate.h
==============================================================================
--- head/sys/netpfil/ipfw/nat64/nat64_translate.h	Wed May  9 11:47:05 2018	(r333402)
+++ head/sys/netpfil/ipfw/nat64/nat64_translate.h	Wed May  9 11:59:24 2018	(r333403)
@@ -30,6 +30,70 @@
 #ifndef	_IP_FW_NAT64_TRANSLATE_H_
 #define	_IP_FW_NAT64_TRANSLATE_H_
 
+struct nat64_stats {
+	uint64_t	opcnt64;	/* 6to4 of packets translated */
+	uint64_t	opcnt46;	/* 4to6 of packets translated */
+	uint64_t	ofrags;		/* number of fragments generated */
+	uint64_t	ifrags;		/* number of fragments received */
+	uint64_t	oerrors;	/* number of output errors */
+	uint64_t	noroute4;
+	uint64_t	noroute6;
+	uint64_t	nomatch4;	/* No addr/port match */
+	uint64_t	noproto;	/* Protocol not supported */
+	uint64_t	nomem;		/* mbufs allocation failed */
+	uint64_t	dropped;	/* number of packets silently
+					 * dropped due to some errors/
+					 * unsupported/etc.
+					 */
+
+	uint64_t	jrequests;	/* number of jobs requests queued */
+	uint64_t	jcalls;		/* number of jobs handler calls */
+	uint64_t	jhostsreq;	/* number of hosts requests */
+	uint64_t	jportreq;
+	uint64_t	jhostfails;
+	uint64_t	jportfails;
+	uint64_t	jmaxlen;
+	uint64_t	jnomem;
+	uint64_t	jreinjected;
+
+	uint64_t	screated;
+	uint64_t	sdeleted;
+	uint64_t	spgcreated;
+	uint64_t	spgdeleted;
+};
+
+#define	IPFW_NAT64_VERSION	1
+#define	NAT64STATS	(sizeof(struct nat64_stats) / sizeof(uint64_t))
+struct nat64_counters {
+	counter_u64_t		cnt[NAT64STATS];
+};
+#define	NAT64STAT_ADD(s, f, v)		\
+    counter_u64_add((s)->cnt[		\
+	offsetof(struct nat64_stats, f) / sizeof(uint64_t)], (v))
+#define	NAT64STAT_INC(s, f)	NAT64STAT_ADD(s, f, 1)
+#define	NAT64STAT_FETCH(s, f)		\
+    counter_u64_fetch((s)->cnt[	\
+	offsetof(struct nat64_stats, f) / sizeof(uint64_t)])
+
+#define	L3HDR(_ip, _t)	((_t)((uint32_t *)(_ip) + (_ip)->ip_hl))
+#define	TCP(p)		((struct tcphdr *)(p))
+#define	UDP(p)		((struct udphdr *)(p))
+#define	ICMP(p)		((struct icmphdr *)(p))
+#define	ICMP6(p)	((struct icmp6_hdr *)(p))
+

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-head mailing list