svn commit: r345275 - in head: sbin/ipfw sys/conf sys/modules/ipfw_nat64 sys/netinet6 sys/netpfil/ipfw/nat64
Andrey V. Elsukov
ae at FreeBSD.org
Mon Mar 18 14:00:22 UTC 2019
Author: ae
Date: Mon Mar 18 14:00:19 2019
New Revision: 345275
URL: https://svnweb.freebsd.org/changeset/base/345275
Log:
Revert r345274. It appears that not all 32-bit architectures have
necessary CK primitives.
Modified:
head/sbin/ipfw/ipfw.8
head/sbin/ipfw/ipfw2.h
head/sbin/ipfw/nat64lsn.c
head/sys/conf/files
head/sys/modules/ipfw_nat64/Makefile
head/sys/netinet6/ip_fw_nat64.h
head/sys/netpfil/ipfw/nat64/nat64lsn.c
head/sys/netpfil/ipfw/nat64/nat64lsn.h
head/sys/netpfil/ipfw/nat64/nat64lsn_control.c
Modified: head/sbin/ipfw/ipfw.8
==============================================================================
--- head/sbin/ipfw/ipfw.8 Mon Mar 18 12:59:08 2019 (r345274)
+++ head/sbin/ipfw/ipfw.8 Mon Mar 18 14:00:19 2019 (r345275)
@@ -3300,7 +3300,6 @@ See
.Sx SYSCTL VARIABLES
for more info.
.Sh IPv6/IPv4 NETWORK ADDRESS AND PROTOCOL TRANSLATION
-.Ss Stateful translation
.Nm
supports in-kernel IPv6/IPv4 network address and protocol translation.
Stateful NAT64 translation allows IPv6-only clients to contact IPv4 servers
@@ -3318,8 +3317,7 @@ to be able use stateful NAT64 translator.
Stateful NAT64 uses a bunch of memory for several types of objects.
When IPv6 client initiates connection, NAT64 translator creates a host entry
in the states table.
-Each host entry uses preallocated IPv4 alias entry.
-Each alias entry has a number of ports group entries allocated on demand.
+Each host entry has a number of ports group entries allocated on demand.
Ports group entries contains connection state entries.
There are several options to control limits and lifetime for these objects.
.Pp
@@ -3339,11 +3337,6 @@ First time an original packet is handled and consumed
and then it is handled again as translated packet.
This behavior can be changed by sysctl variable
.Va net.inet.ip.fw.nat64_direct_output .
-Also translated packet can be tagged using
-.Cm tag
-rule action, and then matched by
-.Cm tagged
-opcode to avoid loops and extra overhead.
.Pp
The stateful NAT64 configuration command is the following:
.Bd -ragged -offset indent
@@ -3371,16 +3364,15 @@ to represent IPv4 addresses. This IPv6 prefix should b
The translator implementation follows RFC6052, that restricts the length of
prefixes to one of following: 32, 40, 48, 56, 64, or 96.
The Well-Known IPv6 Prefix 64:ff9b:: must be 96 bits long.
-The special
-.Ar ::/length
-prefix can be used to handle several IPv6 prefixes with one NAT64 instance.
-The NAT64 instance will determine a destination IPv4 address from prefix
-.Ar length .
-.It Cm states_chunks Ar number
-The number of states chunks in single ports group.
-Each ports group by default can keep 64 state entries in single chunk.
-The above value affects the maximum number of states that can be associated with single IPv4 alias address and port.
-The value must be power of 2, and up to 128.
+.It Cm max_ports Ar number
+Maximum number of ports reserved for upper level protocols to one IPv6 client.
+All reserved ports are divided into chunks between supported protocols.
+The number of connections from one IPv6 client is limited by this option.
+Note that closed TCP connections still remain in the list of connections until
+.Cm tcp_close_age
+interval will not expire.
+Default value is
+.Ar 2048 .
.It Cm host_del_age Ar seconds
The number of seconds until the host entry for a IPv6 client will be deleted
and all its resources will be released due to inactivity.
Modified: head/sbin/ipfw/ipfw2.h
==============================================================================
--- head/sbin/ipfw/ipfw2.h Mon Mar 18 12:59:08 2019 (r345274)
+++ head/sbin/ipfw/ipfw2.h Mon Mar 18 14:00:19 2019 (r345275)
@@ -278,7 +278,6 @@ enum tokens {
TOK_AGG_LEN,
TOK_AGG_COUNT,
TOK_MAX_PORTS,
- TOK_STATES_CHUNKS,
TOK_JMAXLEN,
TOK_PORT_RANGE,
TOK_HOST_DEL_AGE,
Modified: head/sbin/ipfw/nat64lsn.c
==============================================================================
--- head/sbin/ipfw/nat64lsn.c Mon Mar 18 12:59:08 2019 (r345274)
+++ head/sbin/ipfw/nat64lsn.c Mon Mar 18 14:00:19 2019 (r345275)
@@ -87,70 +87,68 @@ nat64lsn_print_states(void *buf)
char sflags[4], *sf, *proto;
ipfw_obj_header *oh;
ipfw_obj_data *od;
- ipfw_nat64lsn_stg_v1 *stg;
- ipfw_nat64lsn_state_v1 *ste;
+ ipfw_nat64lsn_stg *stg;
+ ipfw_nat64lsn_state *ste;
uint64_t next_idx;
int i, sz;
oh = (ipfw_obj_header *)buf;
od = (ipfw_obj_data *)(oh + 1);
- stg = (ipfw_nat64lsn_stg_v1 *)(od + 1);
+ stg = (ipfw_nat64lsn_stg *)(od + 1);
sz = od->head.length - sizeof(*od);
next_idx = 0;
while (sz > 0 && next_idx != 0xFF) {
- next_idx = stg->next.index;
+ next_idx = stg->next_idx;
sz -= sizeof(*stg);
if (stg->count == 0) {
stg++;
continue;
}
- /*
- * NOTE: addresses are in network byte order,
- * ports are in host byte order.
- */
+ switch (stg->proto) {
+ case IPPROTO_TCP:
+ proto = "TCP";
+ break;
+ case IPPROTO_UDP:
+ proto = "UDP";
+ break;
+ case IPPROTO_ICMPV6:
+ proto = "ICMPv6";
+ break;
+ }
+ inet_ntop(AF_INET6, &stg->host6, s, sizeof(s));
inet_ntop(AF_INET, &stg->alias4, a, sizeof(a));
- ste = (ipfw_nat64lsn_state_v1 *)(stg + 1);
+ ste = (ipfw_nat64lsn_state *)(stg + 1);
for (i = 0; i < stg->count && sz > 0; i++) {
sf = sflags;
- inet_ntop(AF_INET6, &ste->host6, s, sizeof(s));
inet_ntop(AF_INET, &ste->daddr, f, sizeof(f));
- switch (ste->proto) {
- case IPPROTO_TCP:
- proto = "TCP";
+ if (stg->proto == IPPROTO_TCP) {
if (ste->flags & 0x02)
*sf++ = 'S';
if (ste->flags & 0x04)
*sf++ = 'E';
if (ste->flags & 0x01)
*sf++ = 'F';
- break;
- case IPPROTO_UDP:
- proto = "UDP";
- break;
- case IPPROTO_ICMP:
- proto = "ICMPv6";
- break;
}
*sf = '\0';
- switch (ste->proto) {
+ switch (stg->proto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
printf("%s:%d\t%s:%d\t%s\t%s\t%d\t%s:%d\n",
s, ste->sport, a, ste->aport, proto,
sflags, ste->idle, f, ste->dport);
break;
- case IPPROTO_ICMP:
+ case IPPROTO_ICMPV6:
printf("%s\t%s\t%s\t\t%d\t%s\n",
s, a, proto, ste->idle, f);
break;
default:
printf("%s\t%s\t%d\t\t%d\t%s\n",
- s, a, ste->proto, ste->idle, f);
+ s, a, stg->proto, ste->idle, f);
}
ste++;
sz -= sizeof(*ste);
}
- stg = (ipfw_nat64lsn_stg_v1 *)ste;
+ stg = (ipfw_nat64lsn_stg *)ste;
}
return (next_idx);
}
@@ -176,7 +174,6 @@ nat64lsn_states_cb(ipfw_nat64lsn_cfg *cfg, const char
err(EX_OSERR, NULL);
do {
oh = (ipfw_obj_header *)buf;
- oh->opheader.version = 1; /* Force using ov new API */
od = (ipfw_obj_data *)(oh + 1);
nat64lsn_fill_ntlv(&oh->ntlv, cfg->name, set);
od->head.type = IPFW_TLV_OBJDATA;
@@ -366,8 +363,12 @@ nat64lsn_parse_int(const char *arg, const char *desc)
static struct _s_x nat64newcmds[] = {
{ "prefix6", TOK_PREFIX6 },
+ { "agg_len", TOK_AGG_LEN }, /* not yet */
+ { "agg_count", TOK_AGG_COUNT }, /* not yet */
+ { "port_range", TOK_PORT_RANGE }, /* not yet */
{ "jmaxlen", TOK_JMAXLEN },
{ "prefix4", TOK_PREFIX4 },
+ { "max_ports", TOK_MAX_PORTS },
{ "host_del_age", TOK_HOST_DEL_AGE },
{ "pg_del_age", TOK_PG_DEL_AGE },
{ "tcp_syn_age", TOK_TCP_SYN_AGE },
@@ -375,13 +376,10 @@ static struct _s_x nat64newcmds[] = {
{ "tcp_est_age", TOK_TCP_EST_AGE },
{ "udp_age", TOK_UDP_AGE },
{ "icmp_age", TOK_ICMP_AGE },
- { "states_chunks",TOK_STATES_CHUNKS },
{ "log", TOK_LOG },
{ "-log", TOK_LOGOFF },
{ "allow_private", TOK_PRIVATE },
{ "-allow_private", TOK_PRIVATEOFF },
- /* for compatibility with old configurations */
- { "max_ports", TOK_MAX_PORTS }, /* unused */
{ NULL, 0 }
};
@@ -438,17 +436,42 @@ nat64lsn_create(const char *name, uint8_t set, int ac,
nat64lsn_parse_prefix(*av, AF_INET6, &cfg->prefix6,
&cfg->plen6);
if (ipfw_check_nat64prefix(&cfg->prefix6,
- cfg->plen6) != 0 &&
- !IN6_IS_ADDR_UNSPECIFIED(&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);
+ ac--; av++;
+ break;
+ case TOK_AGG_COUNT:
+ NEED1("Max per-prefix count required");
+ cfg->agg_prefix_max = nat64lsn_parse_int(*av, opt);
+ ac--; av++;
+ break;
+ case TOK_PORT_RANGE:
+ NEED1("port range x[:y] required");
+ if ((p = strchr(*av, ':')) == NULL)
+ cfg->min_port = (uint16_t)nat64lsn_parse_int(
+ *av, opt);
+ else {
+ *p++ = '\0';
+ cfg->min_port = (uint16_t)nat64lsn_parse_int(
+ *av, opt);
+ cfg->max_port = (uint16_t)nat64lsn_parse_int(
+ p, opt);
+ }
+ ac--; av++;
+ break;
case TOK_JMAXLEN:
NEED1("job queue length required");
cfg->jmaxlen = nat64lsn_parse_int(*av, opt);
ac--; av++;
break;
+#endif
case TOK_MAX_PORTS:
NEED1("Max per-user ports required");
cfg->max_ports = nat64lsn_parse_int(*av, opt);
@@ -496,12 +519,6 @@ nat64lsn_create(const char *name, uint8_t set, int ac,
*av, opt);
ac--; av++;
break;
- case TOK_STATES_CHUNKS:
- NEED1("number of chunks required");
- cfg->states_chunks = (uint8_t)nat64lsn_parse_int(
- *av, opt);
- ac--; av++;
- break;
case TOK_LOG:
cfg->flags |= NAT64_LOG;
break;
@@ -613,12 +630,6 @@ nat64lsn_config(const char *name, uint8_t set, int ac,
*av, opt);
ac--; av++;
break;
- case TOK_STATES_CHUNKS:
- NEED1("number of chunks required");
- cfg->states_chunks = (uint8_t)nat64lsn_parse_int(
- *av, opt);
- ac--; av++;
- break;
case TOK_LOG:
cfg->flags |= NAT64_LOG;
break;
@@ -778,24 +789,31 @@ nat64lsn_show_cb(ipfw_nat64lsn_cfg *cfg, const char *n
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);
- if (co.verbose || cfg->states_chunks > 1)
- printf(" states_chunks %u", cfg->states_chunks);
- if (co.verbose || cfg->nh_delete_delay != NAT64LSN_HOST_AGE)
+#if 0
+ printf("agg_len %u agg_count %u ", cfg->agg_prefix_len,
+ cfg->agg_prefix_max);
+ if (cfg->min_port != NAT64LSN_PORT_MIN ||
+ cfg->max_port != NAT64LSN_PORT_MAX)
+ printf(" port_range %u:%u", cfg->min_port, cfg->max_port);
+ if (cfg->jmaxlen != NAT64LSN_JMAXLEN)
+ printf(" jmaxlen %u ", cfg->jmaxlen);
+#endif
+ if (cfg->max_ports != NAT64LSN_MAX_PORTS)
+ printf(" max_ports %u", cfg->max_ports);
+ if (cfg->nh_delete_delay != NAT64LSN_HOST_AGE)
printf(" host_del_age %u", cfg->nh_delete_delay);
- if (co.verbose || cfg->pg_delete_delay != NAT64LSN_PG_AGE)
+ if (cfg->pg_delete_delay != NAT64LSN_PG_AGE)
printf(" pg_del_age %u ", cfg->pg_delete_delay);
- if (co.verbose || cfg->st_syn_ttl != NAT64LSN_TCP_SYN_AGE)
+ if (cfg->st_syn_ttl != NAT64LSN_TCP_SYN_AGE)
printf(" tcp_syn_age %u", cfg->st_syn_ttl);
- if (co.verbose || cfg->st_close_ttl != NAT64LSN_TCP_FIN_AGE)
+ if (cfg->st_close_ttl != NAT64LSN_TCP_FIN_AGE)
printf(" tcp_close_age %u", cfg->st_close_ttl);
- if (co.verbose || cfg->st_estab_ttl != NAT64LSN_TCP_EST_AGE)
+ if (cfg->st_estab_ttl != NAT64LSN_TCP_EST_AGE)
printf(" tcp_est_age %u", cfg->st_estab_ttl);
- if (co.verbose || cfg->st_udp_ttl != NAT64LSN_UDP_AGE)
+ if (cfg->st_udp_ttl != NAT64LSN_UDP_AGE)
printf(" udp_age %u", cfg->st_udp_ttl);
- if (co.verbose || cfg->st_icmp_ttl != NAT64LSN_ICMP_AGE)
+ if (cfg->st_icmp_ttl != NAT64LSN_ICMP_AGE)
printf(" icmp_age %u", cfg->st_icmp_ttl);
- if (co.verbose || cfg->jmaxlen != NAT64LSN_JMAXLEN)
- printf(" jmaxlen %u ", cfg->jmaxlen);
if (cfg->flags & NAT64_LOG)
printf(" log");
if (cfg->flags & NAT64_ALLOW_PRIVATE)
Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files Mon Mar 18 12:59:08 2019 (r345274)
+++ head/sys/conf/files Mon Mar 18 14:00:19 2019 (r345275)
@@ -4398,9 +4398,9 @@ netpfil/ipfw/nat64/nat64clat.c optional inet inet6 ipf
netpfil/ipfw/nat64/nat64clat_control.c optional inet inet6 ipfirewall \
ipfirewall_nat64
netpfil/ipfw/nat64/nat64lsn.c optional inet inet6 ipfirewall \
- ipfirewall_nat64 compile-with "${NORMAL_C} -I$S/contrib/ck/include"
+ ipfirewall_nat64
netpfil/ipfw/nat64/nat64lsn_control.c optional inet inet6 ipfirewall \
- ipfirewall_nat64 compile-with "${NORMAL_C} -I$S/contrib/ck/include"
+ ipfirewall_nat64
netpfil/ipfw/nat64/nat64stl.c optional inet inet6 ipfirewall \
ipfirewall_nat64
netpfil/ipfw/nat64/nat64stl_control.c optional inet inet6 ipfirewall \
Modified: head/sys/modules/ipfw_nat64/Makefile
==============================================================================
--- head/sys/modules/ipfw_nat64/Makefile Mon Mar 18 12:59:08 2019 (r345274)
+++ head/sys/modules/ipfw_nat64/Makefile Mon Mar 18 14:00:19 2019 (r345275)
@@ -8,6 +8,4 @@ SRCS+= nat64clat.c nat64clat_control.c
SRCS+= nat64lsn.c nat64lsn_control.c
SRCS+= nat64stl.c nat64stl_control.c
-CFLAGS+= -I${SRCTOP}/sys/contrib/ck/include
-
.include <bsd.kmod.mk>
Modified: head/sys/netinet6/ip_fw_nat64.h
==============================================================================
--- head/sys/netinet6/ip_fw_nat64.h Mon Mar 18 12:59:08 2019 (r345274)
+++ head/sys/netinet6/ip_fw_nat64.h Mon Mar 18 14:00:19 2019 (r345275)
@@ -122,7 +122,7 @@ typedef struct _ipfw_nat64clat_cfg {
/*
* NAT64LSN default configuration values
*/
-#define NAT64LSN_MAX_PORTS 2048 /* Unused */
+#define NAT64LSN_MAX_PORTS 2048 /* Max number of ports per host */
#define NAT64LSN_JMAXLEN 2048 /* Max outstanding requests. */
#define NAT64LSN_TCP_SYN_AGE 10 /* State's TTL after SYN received. */
#define NAT64LSN_TCP_EST_AGE (2 * 3600) /* TTL for established connection */
@@ -135,20 +135,16 @@ typedef struct _ipfw_nat64clat_cfg {
typedef struct _ipfw_nat64lsn_cfg {
char name[64]; /* NAT name */
uint32_t flags;
-
- uint32_t max_ports; /* Unused */
- uint32_t agg_prefix_len; /* Unused */
- uint32_t agg_prefix_max; /* Unused */
-
+ uint32_t max_ports; /* Max ports per client */
+ uint32_t agg_prefix_len; /* Prefix length to count */
+ uint32_t agg_prefix_max; /* Max hosts per agg prefix */
struct in_addr prefix4;
uint16_t plen4; /* Prefix length */
uint16_t plen6; /* Prefix length */
struct in6_addr prefix6; /* NAT64 prefix */
uint32_t jmaxlen; /* Max jobqueue length */
-
- uint16_t min_port; /* Unused */
- uint16_t max_port; /* Unused */
-
+ uint16_t min_port; /* Min port group # to use */
+ uint16_t max_port; /* Max port group # to use */
uint16_t nh_delete_delay;/* Stale host delete delay */
uint16_t pg_delete_delay;/* Stale portgroup delete delay */
uint16_t st_syn_ttl; /* TCP syn expire */
@@ -157,7 +153,7 @@ typedef struct _ipfw_nat64lsn_cfg {
uint16_t st_udp_ttl; /* UDP expire */
uint16_t st_icmp_ttl; /* ICMP expire */
uint8_t set; /* Named instance set [0..31] */
- uint8_t states_chunks; /* Number of states chunks per PG */
+ uint8_t spare;
} ipfw_nat64lsn_cfg;
typedef struct _ipfw_nat64lsn_state {
@@ -181,30 +177,5 @@ typedef struct _ipfw_nat64lsn_stg {
uint32_t spare2;
} ipfw_nat64lsn_stg;
-typedef struct _ipfw_nat64lsn_state_v1 {
- struct in6_addr host6; /* Bound IPv6 host */
- struct in_addr daddr; /* Remote IPv4 address */
- uint16_t dport; /* Remote destination port */
- uint16_t aport; /* Local alias port */
- uint16_t sport; /* Source port */
- uint16_t spare;
- uint16_t idle; /* Last used time */
- uint8_t flags; /* State flags */
- uint8_t proto; /* protocol */
-} ipfw_nat64lsn_state_v1;
-
-typedef struct _ipfw_nat64lsn_stg_v1 {
- union nat64lsn_pgidx {
- uint64_t index;
- struct {
- uint8_t chunk; /* states chunk */
- uint8_t proto; /* protocol */
- uint16_t port; /* base port */
- in_addr_t addr; /* alias address */
- };
- } next; /* next state index */
- struct in_addr alias4; /* IPv4 alias address */
- uint32_t count; /* Number of states */
-} ipfw_nat64lsn_stg_v1;
-
#endif /* _NETINET6_IP_FW_NAT64_H_ */
+
Modified: head/sys/netpfil/ipfw/nat64/nat64lsn.c
==============================================================================
--- head/sys/netpfil/ipfw/nat64/nat64lsn.c Mon Mar 18 12:59:08 2019 (r345274)
+++ head/sys/netpfil/ipfw/nat64/nat64lsn.c Mon Mar 18 14:00:19 2019 (r345275)
@@ -33,17 +33,16 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/counter.h>
-#include <sys/ck.h>
-#include <sys/epoch.h>
#include <sys/errno.h>
-#include <sys/hash.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/module.h>
#include <sys/rmlock.h>
+#include <sys/rwlock.h>
#include <sys/socket.h>
+#include <sys/queue.h>
#include <sys/syslog.h>
#include <sys/sysctl.h>
@@ -72,22 +71,17 @@ __FBSDID("$FreeBSD$");
MALLOC_DEFINE(M_NAT64LSN, "NAT64LSN", "NAT64LSN");
-static epoch_t nat64lsn_epoch;
-#define NAT64LSN_EPOCH_ENTER(et) epoch_enter_preempt(nat64lsn_epoch, &(et))
-#define NAT64LSN_EPOCH_EXIT(et) epoch_exit_preempt(nat64lsn_epoch, &(et))
-#define NAT64LSN_EPOCH_WAIT() epoch_wait_preempt(nat64lsn_epoch)
-#define NAT64LSN_EPOCH_ASSERT() MPASS(in_epoch(nat64lsn_epoch))
-#define NAT64LSN_EPOCH_CALL(c, f) epoch_call(nat64lsn_epoch, (c), (f))
+static void nat64lsn_periodic(void *data);
+#define PERIODIC_DELAY 4
+static uint8_t nat64lsn_proto_map[256];
+uint8_t nat64lsn_rproto_map[NAT_MAX_PROTO];
-static uma_zone_t nat64lsn_host_zone;
-static uma_zone_t nat64lsn_pgchunk_zone;
-static uma_zone_t nat64lsn_pg_zone;
-static uma_zone_t nat64lsn_aliaslink_zone;
-static uma_zone_t nat64lsn_state_zone;
-static uma_zone_t nat64lsn_job_zone;
+#define NAT64_FLAG_FIN 0x01 /* FIN was seen */
+#define NAT64_FLAG_SYN 0x02 /* First syn in->out */
+#define NAT64_FLAG_ESTAB 0x04 /* Packet with Ack */
+#define NAT64_FLAGS_TCP (NAT64_FLAG_SYN|NAT64_FLAG_ESTAB|NAT64_FLAG_FIN)
-static void nat64lsn_periodic(void *data);
-#define PERIODIC_DELAY 4
+#define NAT64_FLAG_RDR 0x80 /* Port redirect */
#define NAT64_LOOKUP(chain, cmd) \
(struct nat64lsn_cfg *)SRV_OBJECT((chain), (cmd)->arg1)
/*
@@ -97,33 +91,25 @@ static void nat64lsn_periodic(void *data);
enum nat64lsn_jtype {
JTYPE_NEWHOST = 1,
JTYPE_NEWPORTGROUP,
- JTYPE_DESTROY,
+ JTYPE_DELPORTGROUP,
};
struct nat64lsn_job_item {
- STAILQ_ENTRY(nat64lsn_job_item) entries;
+ TAILQ_ENTRY(nat64lsn_job_item) next;
enum nat64lsn_jtype jtype;
-
- union {
- struct { /* used by JTYPE_NEWHOST, JTYPE_NEWPORTGROUP */
- struct mbuf *m;
- struct nat64lsn_host *host;
- struct nat64lsn_state *state;
- uint32_t src6_hval;
- uint32_t state_hval;
- struct ipfw_flow_id f_id;
- in_addr_t faddr;
- uint16_t port;
- uint8_t proto;
- uint8_t done;
- };
- struct { /* used by JTYPE_DESTROY */
- struct nat64lsn_hosts_slist hosts;
- struct nat64lsn_pg_slist portgroups;
- struct nat64lsn_pgchunk *pgchunk;
- struct epoch_context epoch_ctx;
- };
- };
+ struct nat64lsn_host *nh;
+ struct nat64lsn_portgroup *pg;
+ void *spare_idx;
+ struct in6_addr haddr;
+ uint8_t nat_proto;
+ uint8_t done;
+ int needs_idx;
+ int delcount;
+ unsigned int fhash; /* Flow hash */
+ uint32_t aaddr; /* Last used address (net) */
+ struct mbuf *m;
+ struct ipfw_flow_id f_id;
+ uint64_t delmask[NAT64LSN_PGPTRNMASK];
};
static struct mtx jmtx;
@@ -132,278 +118,143 @@ static struct mtx jmtx;
#define JQUEUE_LOCK() mtx_lock(&jmtx)
#define JQUEUE_UNLOCK() mtx_unlock(&jmtx)
-static int nat64lsn_alloc_host(struct nat64lsn_cfg *cfg,
- struct nat64lsn_job_item *ji);
-static int nat64lsn_alloc_pg(struct nat64lsn_cfg *cfg,
- struct nat64lsn_job_item *ji);
-static struct nat64lsn_job_item *nat64lsn_create_job(
- struct nat64lsn_cfg *cfg, int jtype);
static void nat64lsn_enqueue_job(struct nat64lsn_cfg *cfg,
struct nat64lsn_job_item *ji);
-static void nat64lsn_job_destroy(epoch_context_t ctx);
-static void nat64lsn_destroy_host(struct nat64lsn_host *host);
-static void nat64lsn_destroy_pg(struct nat64lsn_pg *pg);
+static void nat64lsn_enqueue_jobs(struct nat64lsn_cfg *cfg,
+ struct nat64lsn_job_head *jhead, int jlen);
+static struct nat64lsn_job_item *nat64lsn_create_job(struct nat64lsn_cfg *cfg,
+ const struct ipfw_flow_id *f_id, int jtype);
+static int nat64lsn_request_portgroup(struct nat64lsn_cfg *cfg,
+ const struct ipfw_flow_id *f_id, struct mbuf **pm, uint32_t aaddr,
+ int needs_idx);
+static int nat64lsn_request_host(struct nat64lsn_cfg *cfg,
+ const struct ipfw_flow_id *f_id, struct mbuf **pm);
static int nat64lsn_translate4(struct nat64lsn_cfg *cfg,
- const struct ipfw_flow_id *f_id, struct mbuf **mp);
+ const struct ipfw_flow_id *f_id, struct mbuf **pm);
static int nat64lsn_translate6(struct nat64lsn_cfg *cfg,
- struct ipfw_flow_id *f_id, struct mbuf **mp);
-static int nat64lsn_translate6_internal(struct nat64lsn_cfg *cfg,
- struct mbuf **mp, struct nat64lsn_state *state, uint8_t flags);
+ struct ipfw_flow_id *f_id, struct mbuf **pm);
-#define NAT64_BIT_TCP_FIN 0 /* FIN was seen */
-#define NAT64_BIT_TCP_SYN 1 /* First syn in->out */
-#define NAT64_BIT_TCP_ESTAB 2 /* Packet with Ack */
-#define NAT64_BIT_READY_IPV4 6 /* state is ready for translate4 */
-#define NAT64_BIT_STALE 7 /* state is going to be expired */
+static int alloc_portgroup(struct nat64lsn_job_item *ji);
+static void destroy_portgroup(struct nat64lsn_portgroup *pg);
+static void destroy_host6(struct nat64lsn_host *nh);
+static int alloc_host6(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji);
-#define NAT64_FLAG_FIN (1 << NAT64_BIT_TCP_FIN)
-#define NAT64_FLAG_SYN (1 << NAT64_BIT_TCP_SYN)
-#define NAT64_FLAG_ESTAB (1 << NAT64_BIT_TCP_ESTAB)
-#define NAT64_FLAGS_TCP (NAT64_FLAG_SYN|NAT64_FLAG_ESTAB|NAT64_FLAG_FIN)
+static int attach_portgroup(struct nat64lsn_cfg *cfg,
+ struct nat64lsn_job_item *ji);
+static int attach_host6(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji);
-#define NAT64_FLAG_READY (1 << NAT64_BIT_READY_IPV4)
-#define NAT64_FLAG_STALE (1 << NAT64_BIT_STALE)
-static inline uint8_t
-convert_tcp_flags(uint8_t flags)
-{
- uint8_t result;
+/* XXX tmp */
+static uma_zone_t nat64lsn_host_zone;
+static uma_zone_t nat64lsn_pg_zone;
+static uma_zone_t nat64lsn_pgidx_zone;
- result = flags & (TH_FIN|TH_SYN);
- result |= (flags & TH_RST) >> 2; /* Treat RST as FIN */
- result |= (flags & TH_ACK) >> 2; /* Treat ACK as estab */
+static unsigned int nat64lsn_periodic_chkstates(struct nat64lsn_cfg *cfg,
+ struct nat64lsn_host *nh);
- return (result);
-}
+#define I6_hash(x) (djb_hash((const unsigned char *)(x), 16))
+#define I6_first(_ph, h) (_ph)[h]
+#define I6_next(x) (x)->next
+#define I6_val(x) (&(x)->addr)
+#define I6_cmp(a, b) IN6_ARE_ADDR_EQUAL(a, b)
+#define I6_lock(a, b)
+#define I6_unlock(a, b)
-static void
-nat64lsn_log(struct pfloghdr *plog, struct mbuf *m, sa_family_t family,
- uintptr_t state)
-{
+#define I6HASH_FIND(_cfg, _res, _a) \
+ CHT_FIND(_cfg->ih, _cfg->ihsize, I6_, _res, _a)
+#define I6HASH_INSERT(_cfg, _i) \
+ CHT_INSERT_HEAD(_cfg->ih, _cfg->ihsize, I6_, _i)
+#define I6HASH_REMOVE(_cfg, _res, _tmp, _a) \
+ CHT_REMOVE(_cfg->ih, _cfg->ihsize, I6_, _res, _tmp, _a)
- memset(plog, 0, sizeof(*plog));
- plog->length = PFLOG_REAL_HDRLEN;
- plog->af = family;
- plog->action = PF_NAT;
- plog->dir = PF_IN;
- plog->rulenr = htonl(state >> 32);
- plog->subrulenr = htonl(state & 0xffffffff);
- plog->ruleset[0] = '\0';
- strlcpy(plog->ifname, "NAT64LSN", sizeof(plog->ifname));
- ipfw_bpf_mtap2(plog, PFLOG_HDRLEN, m);
-}
+#define I6HASH_FOREACH_SAFE(_cfg, _x, _tmp, _cb, _arg) \
+ CHT_FOREACH_SAFE(_cfg->ih, _cfg->ihsize, I6_, _x, _tmp, _cb, _arg)
-#define HVAL(p, n, s) jenkins_hash32((const uint32_t *)(p), (n), (s))
-#define HOST_HVAL(c, a) HVAL((a),\
- sizeof(struct in6_addr) / sizeof(uint32_t), (c)->hash_seed)
-#define HOSTS(c, v) ((c)->hosts_hash[(v) & ((c)->hosts_hashsize - 1)])
+#define HASH_IN4(x) djb_hash((const unsigned char *)(x), 8)
-#define ALIASLINK_HVAL(c, f) HVAL(&(f)->dst_ip6,\
- sizeof(struct in6_addr) * 2 / sizeof(uint32_t), (c)->hash_seed)
-#define ALIAS_BYHASH(c, v) \
- ((c)->aliases[(v) & ((1 << (32 - (c)->plen4)) - 1)])
-static struct nat64lsn_aliaslink*
-nat64lsn_get_aliaslink(struct nat64lsn_cfg *cfg __unused,
- struct nat64lsn_host *host, const struct ipfw_flow_id *f_id __unused)
+static unsigned
+djb_hash(const unsigned char *h, const int len)
{
+ unsigned int result = 0;
+ int i;
- /*
- * We can implement some different algorithms how
- * select an alias address.
- * XXX: for now we use first available.
- */
- return (CK_SLIST_FIRST(&host->aliases));
+ for (i = 0; i < len; i++)
+ result = 33 * result ^ h[i];
+
+ return (result);
}
-#define FADDR_CHUNK(p, a) ((a) & ((p)->chunks_count - 1))
-#define FREEMASK_CHUNK(p, v) \
- ((p)->chunks_count == 1 ? &(p)->freemask : \
- &((p)->freemask_chunk[FADDR_CHUNK(p, v)]))
-#define STATES_CHUNK(p, v) \
- ((p)->chunks_count == 1 ? (p)->states : \
- ((p)->states_chunk[FADDR_CHUNK(p, v)]))
-#define STATE_HVAL(c, d) HVAL((d), 2, (c)->hash_seed)
-#define STATE_HASH(h, v) \
- ((h)->states_hash[(v) & ((h)->states_hashsize - 1)])
-
-#define NAT64LSN_TRY_PGCNT 32
-static struct nat64lsn_pg*
-nat64lsn_get_pg(uint32_t *chunkmask, uint32_t *pgmask,
- struct nat64lsn_pgchunk **chunks, struct nat64lsn_pg **pgptr,
- uint32_t *pgidx, in_addr_t faddr)
+/*
+static size_t
+bitmask_size(size_t num, int *level)
{
- struct nat64lsn_pg *pg, *oldpg;
- uint32_t idx, oldidx;
- int cnt;
+ size_t x;
+ int c;
- cnt = 0;
- /* First try last used PG */
- oldpg = pg = ck_pr_load_ptr(pgptr);
- idx = oldidx = ck_pr_load_32(pgidx);
- /* If pgidx is out of range, reset it to the first pgchunk */
- if (!ISSET32(*chunkmask, idx / 32))
- idx = 0;
- do {
- ck_pr_fence_load();
- if (pg != NULL &&
- bitcount64(*FREEMASK_CHUNK(pg, faddr)) > 0) {
- /*
- * If last used PG has not free states,
- * try to update pointer.
- * NOTE: it can be already updated by jobs handler,
- * thus we use CAS operation.
- */
- if (cnt > 0)
- ck_pr_cas_ptr(pgptr, oldpg, pg);
- return (pg);
- }
- /* Stop if idx is out of range */
- if (!ISSET32(*chunkmask, idx / 32))
- break;
+ for (c = 0, x = num; num > 1; num /= 64, c++)
+ ;
- if (ISSET32(pgmask[idx / 32], idx % 32))
- pg = ck_pr_load_ptr(
- &chunks[idx / 32]->pgptr[idx % 32]);
- else
- pg = NULL;
+ return (x);
+}
- idx++;
- } while (++cnt < NAT64LSN_TRY_PGCNT);
+static void
+bitmask_prepare(uint64_t *pmask, size_t bufsize, int level)
+{
+ size_t x, z;
- /* If pgidx is out of range, reset it to the first pgchunk */
- if (!ISSET32(*chunkmask, idx / 32))
- idx = 0;
- ck_pr_cas_32(pgidx, oldidx, idx);
- return (NULL);
+ memset(pmask, 0xFF, bufsize);
+ for (x = 0, z = 1; level > 1; x += z, z *= 64, level--)
+ ;
+ pmask[x] ~= 0x01;
}
+*/
-static struct nat64lsn_state*
-nat64lsn_get_state6to4(struct nat64lsn_cfg *cfg, struct nat64lsn_host *host,
- const struct ipfw_flow_id *f_id, uint32_t hval, in_addr_t faddr,
- uint16_t port, uint8_t proto)
+static void
+nat64lsn_log(struct pfloghdr *plog, struct mbuf *m, sa_family_t family,
+ uint32_t n, uint32_t sn)
{
- struct nat64lsn_aliaslink *link;
- struct nat64lsn_state *state;
- struct nat64lsn_pg *pg;
- int i, offset;
- NAT64LSN_EPOCH_ASSERT();
-
- /* Check that we already have state for given arguments */
- CK_SLIST_FOREACH(state, &STATE_HASH(host, hval), entries) {
- if (state->proto == proto && state->ip_dst == faddr &&
- state->sport == port && state->dport == f_id->dst_port)
- return (state);
- }
-
- link = nat64lsn_get_aliaslink(cfg, host, f_id);
- if (link == NULL)
- return (NULL);
-
- switch (proto) {
- case IPPROTO_TCP:
- pg = nat64lsn_get_pg(
- &link->alias->tcp_chunkmask, link->alias->tcp_pgmask,
- link->alias->tcp, &link->alias->tcp_pg,
- &link->alias->tcp_pgidx, faddr);
- break;
- case IPPROTO_UDP:
- pg = nat64lsn_get_pg(
- &link->alias->udp_chunkmask, link->alias->udp_pgmask,
- link->alias->udp, &link->alias->udp_pg,
- &link->alias->udp_pgidx, faddr);
- break;
- case IPPROTO_ICMP:
- pg = nat64lsn_get_pg(
- &link->alias->icmp_chunkmask, link->alias->icmp_pgmask,
- link->alias->icmp, &link->alias->icmp_pg,
- &link->alias->icmp_pgidx, faddr);
- break;
- default:
- panic("%s: wrong proto %d", __func__, proto);
- }
- if (pg == NULL)
- return (NULL);
-
- /* Check that PG has some free states */
- state = NULL;
- i = bitcount64(*FREEMASK_CHUNK(pg, faddr));
- while (i-- > 0) {
- offset = ffsll(*FREEMASK_CHUNK(pg, faddr));
- if (offset == 0) {
- /*
- * We lost the race.
- * No more free states in this PG.
- */
- break;
- }
-
- /* Lets try to atomically grab the state */
- if (ck_pr_btr_64(FREEMASK_CHUNK(pg, faddr), offset - 1)) {
- state = &STATES_CHUNK(pg, faddr)->state[offset - 1];
- /* Initialize */
- state->flags = proto != IPPROTO_TCP ? 0 :
- convert_tcp_flags(f_id->_flags);
- state->proto = proto;
- state->aport = pg->base_port + offset - 1;
- state->dport = f_id->dst_port;
- state->sport = port;
- state->ip6_dst = f_id->dst_ip6;
- state->ip_dst = faddr;
- state->ip_src = link->alias->addr;
- state->hval = hval;
- state->host = host;
- SET_AGE(state->timestamp);
-
- /* Insert new state into host's hash table */
- HOST_LOCK(host);
- CK_SLIST_INSERT_HEAD(&STATE_HASH(host, hval),
- state, entries);
- host->states_count++;
- /*
- * XXX: In case if host is going to be expired,
- * reset NAT64LSN_DEADHOST flag.
- */
- host->flags &= ~NAT64LSN_DEADHOST;
- HOST_UNLOCK(host);
- NAT64STAT_INC(&cfg->base.stats, screated);
- /* Mark the state as ready for translate4 */
- ck_pr_fence_store();
- ck_pr_bts_32(&state->flags, NAT64_BIT_READY_IPV4);
- break;
- }
- }
- return (state);
+ memset(plog, 0, sizeof(*plog));
+ plog->length = PFLOG_REAL_HDRLEN;
+ plog->af = family;
+ plog->action = PF_NAT;
+ plog->dir = PF_IN;
+ plog->rulenr = htonl(n);
+ plog->subrulenr = htonl(sn);
+ plog->ruleset[0] = '\0';
+ strlcpy(plog->ifname, "NAT64LSN", sizeof(plog->ifname));
+ ipfw_bpf_mtap2(plog, PFLOG_HDRLEN, m);
}
-
/*
* Inspects icmp packets to see if the message contains different
* packet header so we need to alter @addr and @port.
*/
static int
-inspect_icmp_mbuf(struct mbuf **mp, uint8_t *proto, uint32_t *addr,
+inspect_icmp_mbuf(struct mbuf **m, uint8_t *nat_proto, uint32_t *addr,
uint16_t *port)
{
- struct icmp *icmp;
struct ip *ip;
+ struct tcphdr *tcp;
+ struct udphdr *udp;
+ struct icmphdr *icmp;
int off;
- uint8_t inner_proto;
+ uint8_t proto;
- ip = mtod(*mp, struct ip *); /* Outer IP header */
+ ip = mtod(*m, struct ip *); /* Outer IP header */
off = (ip->ip_hl << 2) + ICMP_MINLEN;
- if ((*mp)->m_len < off)
- *mp = m_pullup(*mp, off);
- if (*mp == NULL)
+ if ((*m)->m_len < off)
+ *m = m_pullup(*m, off);
+ if (*m == NULL)
return (ENOMEM);
- ip = mtod(*mp, struct ip *); /* Outer IP header */
- icmp = L3HDR(ip, struct icmp *);
+ ip = mtod(*m, struct ip *); /* Outer IP header */
+ icmp = L3HDR(ip, struct icmphdr *);
switch (icmp->icmp_type) {
case ICMP_ECHO:
case ICMP_ECHOREPLY:
/* Use icmp ID as distinguisher */
- *port = ntohs(icmp->icmp_id);
+ *port = ntohs(*((uint16_t *)(icmp + 1)));
return (0);
case ICMP_UNREACH:
case ICMP_TIMXCEED:
@@ -415,133 +266,90 @@ inspect_icmp_mbuf(struct mbuf **mp, uint8_t *proto, ui
* ICMP_UNREACH and ICMP_TIMXCEED contains IP header + 64 bits
* of ULP header.
*/
- if ((*mp)->m_pkthdr.len < off + sizeof(struct ip) + ICMP_MINLEN)
+ if ((*m)->m_pkthdr.len < off + sizeof(struct ip) + ICMP_MINLEN)
return (EINVAL);
- if ((*mp)->m_len < off + sizeof(struct ip) + ICMP_MINLEN)
- *mp = m_pullup(*mp, off + sizeof(struct ip) + ICMP_MINLEN);
- if (*mp == NULL)
+ if ((*m)->m_len < off + sizeof(struct ip) + ICMP_MINLEN)
+ *m = m_pullup(*m, off + sizeof(struct ip) + ICMP_MINLEN);
+ if (*m == NULL)
return (ENOMEM);
- ip = mtodo(*mp, off); /* Inner IP header */
- inner_proto = ip->ip_p;
+ ip = mtodo(*m, off); /* Inner IP header */
+ proto = ip->ip_p;
off += ip->ip_hl << 2; /* Skip inner IP header */
*addr = ntohl(ip->ip_src.s_addr);
- if ((*mp)->m_len < off + ICMP_MINLEN)
- *mp = m_pullup(*mp, off + ICMP_MINLEN);
- if (*mp == NULL)
+ if ((*m)->m_len < off + ICMP_MINLEN)
+ *m = m_pullup(*m, off + ICMP_MINLEN);
+ if (*m == NULL)
return (ENOMEM);
- switch (inner_proto) {
+ switch (proto) {
case IPPROTO_TCP:
+ tcp = mtodo(*m, off);
+ *nat_proto = NAT_PROTO_TCP;
+ *port = ntohs(tcp->th_sport);
+ return (0);
case IPPROTO_UDP:
- /* Copy source port from the header */
- *port = ntohs(*((uint16_t *)mtodo(*mp, off)));
- *proto = inner_proto;
+ udp = mtodo(*m, off);
+ *nat_proto = NAT_PROTO_UDP;
+ *port = ntohs(udp->uh_sport);
return (0);
case IPPROTO_ICMP:
/*
* We will translate only ICMP errors for our ICMP
* echo requests.
*/
- icmp = mtodo(*mp, off);
+ icmp = mtodo(*m, off);
if (icmp->icmp_type != ICMP_ECHO)
return (EOPNOTSUPP);
- *port = ntohs(icmp->icmp_id);
+ *port = ntohs(*((uint16_t *)(icmp + 1)));
return (0);
};
return (EOPNOTSUPP);
}
-static struct nat64lsn_state*
-nat64lsn_get_state4to6(struct nat64lsn_cfg *cfg, struct nat64lsn_alias *alias,
- in_addr_t faddr, uint16_t port, uint8_t proto)
+static inline uint8_t
+convert_tcp_flags(uint8_t flags)
{
- struct nat64lsn_state *state;
- struct nat64lsn_pg *pg;
- int chunk_idx, pg_idx, state_idx;
+ uint8_t result;
- NAT64LSN_EPOCH_ASSERT();
+ result = flags & (TH_FIN|TH_SYN);
+ result |= (flags & TH_RST) >> 2; /* Treat RST as FIN */
+ result |= (flags & TH_ACK) >> 2; /* Treat ACK as estab */
- if (port < NAT64_MIN_PORT)
- return (NULL);
- /*
- * Alias keeps 32 pgchunks for each protocol.
- * Each pgchunk has 32 pointers to portgroup.
- * Each portgroup has 64 states for ports.
- */
- port -= NAT64_MIN_PORT;
- chunk_idx = port / 2048;
-
- port -= chunk_idx * 2048;
- pg_idx = port / 64;
- state_idx = port % 64;
-
- /*
- * First check in proto_chunkmask that we have allocated PG chunk.
- * Then check in proto_pgmask that we have valid PG pointer.
- */
- pg = NULL;
- switch (proto) {
- case IPPROTO_TCP:
- if (ISSET32(alias->tcp_chunkmask, chunk_idx) &&
- ISSET32(alias->tcp_pgmask[chunk_idx], pg_idx)) {
- pg = alias->tcp[chunk_idx]->pgptr[pg_idx];
- break;
- }
- return (NULL);
- case IPPROTO_UDP:
- if (ISSET32(alias->udp_chunkmask, chunk_idx) &&
- ISSET32(alias->udp_pgmask[chunk_idx], pg_idx)) {
- pg = alias->udp[chunk_idx]->pgptr[pg_idx];
- break;
- }
- return (NULL);
- case IPPROTO_ICMP:
- if (ISSET32(alias->icmp_chunkmask, chunk_idx) &&
- ISSET32(alias->icmp_pgmask[chunk_idx], pg_idx)) {
- pg = alias->icmp[chunk_idx]->pgptr[pg_idx];
- break;
- }
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-all
mailing list