freebsd-dev/sys/netpfil/ipfw/nat64/nat64lsn.h
Andrey V. Elsukov d18c1f26a4 Reapply r345274 with build fixes for 32-bit architectures.
Update NAT64LSN implementation:

  o most of data structures and relations were modified to be able support
    large number of translation states. Now each supported protocol can
    use full ports range. Ports groups now are belongs to IPv4 alias
    addresses, not hosts. Each ports group can keep several states chunks.
    This is controlled with new `states_chunks` config option. States
    chunks allow to have several translation states for single alias address
    and port, but for different destination addresses.
  o by default all hash tables now use jenkins hash.
  o ConcurrencyKit and epoch(9) is used to make NAT64LSN lockless on fast path.
  o one NAT64LSN instance now can be used to handle several IPv6 prefixes,
    special prefix "::" value should be used for this purpose when instance
    is created.
  o due to modified internal data structures relations, the socket opcode
    that does states listing was changed.

Obtained from:	Yandex LLC
MFC after:	1 month
Sponsored by:	Yandex LLC
2019-03-19 10:57:03 +00:00

256 lines
7.9 KiB
C

/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2015-2019 Yandex LLC
* Copyright (c) 2015 Alexander V. Chernikov <melifaro@FreeBSD.org>
* Copyright (c) 2015-2019 Andrey V. Elsukov <ae@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _IP_FW_NAT64LSN_H_
#define _IP_FW_NAT64LSN_H_
#include "ip_fw_nat64.h"
#include "nat64_translate.h"
#define NAT64_MIN_PORT 1024
struct nat64lsn_host;
struct nat64lsn_alias;
struct nat64lsn_state {
/* IPv6 host entry keeps hash table to speedup state lookup */
CK_SLIST_ENTRY(nat64lsn_state) entries;
struct nat64lsn_host *host;
struct in6_addr ip6_dst; /* Destination IPv6 address */
in_addr_t ip_src; /* Alias IPv4 address */
in_addr_t ip_dst; /* Destination IPv4 address */
uint16_t dport; /* Destination port */
uint16_t sport; /* Source port */
uint32_t hval;
uint32_t flags; /* Internal flags */
uint16_t aport;
uint16_t timestamp; /* last used */
uint8_t proto;
uint8_t _spare[7];
};
struct nat64lsn_states_chunk {
struct nat64lsn_state state[64];
};
#define ISSET64(mask, bit) ((mask) & ((uint64_t)1 << (bit)))
#define ISSET32(mask, bit) ((mask) & ((uint32_t)1 << (bit)))
struct nat64lsn_pg {
CK_SLIST_ENTRY(nat64lsn_pg) entries;
uint16_t base_port;
uint16_t timestamp;
uint8_t proto;
uint8_t chunks_count;
uint8_t spare[2];
union {
uint64_t freemask64;
uint32_t freemask32[2];
uint64_t *freemask64_chunk;
uint32_t *freemask32_chunk;
void *freemask_chunk;
};
union {
struct nat64lsn_states_chunk *states;
struct nat64lsn_states_chunk **states_chunk;
};
};
#define CHUNK_BY_FADDR(p, a) ((a) & ((p)->chunks_count - 1))
#ifdef __LP64__
#define FREEMASK_CHUNK(p, v) \
((p)->chunks_count == 1 ? &(p)->freemask64 : \
&(p)->freemask64_chunk[CHUNK_BY_FADDR(p, v)])
#define FREEMASK_BITCOUNT(pg, faddr) \
bitcount64(*FREEMASK_CHUNK((pg), (faddr)))
#else
#define FREEMASK_CHUNK(p, v) \
((p)->chunks_count == 1 ? &(p)->freemask32[0] : \
&(p)->freemask32_chunk[CHUNK_BY_FADDR(p, v) * 2])
#define FREEMASK_BITCOUNT(pg, faddr) \
bitcount64(*(uint64_t *)FREEMASK_CHUNK((pg), (faddr)))
#endif /* !__LP64__ */
struct nat64lsn_pgchunk {
struct nat64lsn_pg *pgptr[32];
};
struct nat64lsn_aliaslink {
CK_SLIST_ENTRY(nat64lsn_aliaslink) alias_entries;
CK_SLIST_ENTRY(nat64lsn_aliaslink) host_entries;
struct nat64lsn_alias *alias;
};
CK_SLIST_HEAD(nat64lsn_aliaslink_slist, nat64lsn_aliaslink);
CK_SLIST_HEAD(nat64lsn_states_slist, nat64lsn_state);
CK_SLIST_HEAD(nat64lsn_hosts_slist, nat64lsn_host);
CK_SLIST_HEAD(nat64lsn_pg_slist, nat64lsn_pg);
struct nat64lsn_alias {
struct nat64lsn_aliaslink_slist hosts;
struct nat64lsn_pg_slist portgroups;
struct mtx lock;
in_addr_t addr; /* host byte order */
uint32_t hosts_count;
uint32_t portgroups_count;
uint32_t tcp_chunkmask;
uint32_t udp_chunkmask;
uint32_t icmp_chunkmask;
uint32_t tcp_pgidx;
uint32_t udp_pgidx;
uint32_t icmp_pgidx;
uint16_t timestamp;
uint16_t spare;
uint32_t tcp_pgmask[32];
uint32_t udp_pgmask[32];
uint32_t icmp_pgmask[32];
struct nat64lsn_pgchunk *tcp[32];
struct nat64lsn_pgchunk *udp[32];
struct nat64lsn_pgchunk *icmp[32];
/* pointer to PG that can be used for faster state allocation */
struct nat64lsn_pg *tcp_pg;
struct nat64lsn_pg *udp_pg;
struct nat64lsn_pg *icmp_pg;
};
#define ALIAS_LOCK_INIT(p) \
mtx_init(&(p)->lock, "alias_lock", NULL, MTX_DEF)
#define ALIAS_LOCK_DESTROY(p) mtx_destroy(&(p)->lock)
#define ALIAS_LOCK(p) mtx_lock(&(p)->lock)
#define ALIAS_UNLOCK(p) mtx_unlock(&(p)->lock)
#define NAT64LSN_HSIZE 256
#define NAT64LSN_MAX_HSIZE 4096
#define NAT64LSN_HOSTS_HSIZE 1024
struct nat64lsn_host {
struct in6_addr addr;
struct nat64lsn_aliaslink_slist aliases;
struct nat64lsn_states_slist *states_hash;
CK_SLIST_ENTRY(nat64lsn_host) entries;
uint32_t states_count;
uint32_t hval;
uint32_t flags;
#define NAT64LSN_DEADHOST 1
#define NAT64LSN_GROWHASH 2
uint16_t states_hashsize;
uint16_t timestamp;
struct mtx lock;
};
#define HOST_LOCK_INIT(p) \
mtx_init(&(p)->lock, "host_lock", NULL, MTX_DEF|MTX_NEW)
#define HOST_LOCK_DESTROY(p) mtx_destroy(&(p)->lock)
#define HOST_LOCK(p) mtx_lock(&(p)->lock)
#define HOST_UNLOCK(p) mtx_unlock(&(p)->lock)
VNET_DECLARE(uint16_t, nat64lsn_eid);
#define V_nat64lsn_eid VNET(nat64lsn_eid)
#define IPFW_TLV_NAT64LSN_NAME IPFW_TLV_EACTION_NAME(V_nat64lsn_eid)
/* Timestamp macro */
#define _CT ((int)time_uptime % 65536)
#define SET_AGE(x) (x) = _CT
#define GET_AGE(x) ((_CT >= (x)) ? _CT - (x): (int)65536 + _CT - (x))
STAILQ_HEAD(nat64lsn_job_head, nat64lsn_job_item);
struct nat64lsn_cfg {
struct named_object no;
struct nat64lsn_hosts_slist *hosts_hash;
struct nat64lsn_alias *aliases; /* array of aliases */
struct mtx lock;
uint32_t hosts_hashsize;
uint32_t hash_seed;
uint32_t prefix4; /* IPv4 prefix */
uint32_t pmask4; /* IPv4 prefix mask */
uint8_t plen4;
uint8_t nomatch_verdict;/* Return value on no-match */
uint32_t hosts_count; /* Number of items in host hash */
uint32_t states_chunks; /* Number of states chunks per PG */
uint32_t jmaxlen; /* Max jobqueue length */
uint16_t host_delete_delay; /* Stale host delete delay */
uint16_t pgchunk_delete_delay;
uint16_t pg_delete_delay; /* Stale portgroup del delay */
uint16_t st_syn_ttl; /* TCP syn expire */
uint16_t st_close_ttl; /* TCP fin expire */
uint16_t st_estab_ttl; /* TCP established expire */
uint16_t st_udp_ttl; /* UDP expire */
uint16_t st_icmp_ttl; /* ICMP expire */
struct nat64_config base;
#define NAT64LSN_FLAGSMASK (NAT64_LOG | NAT64_ALLOW_PRIVATE)
#define NAT64LSN_ANYPREFIX 0x00000100
struct mtx periodic_lock;
struct callout periodic;
struct callout jcallout;
struct vnet *vp;
struct nat64lsn_job_head jhead;
int jlen;
char name[64]; /* Nat instance name */
};
/* CFG_LOCK protects cfg->hosts_hash from modification */
#define CFG_LOCK_INIT(p) \
mtx_init(&(p)->lock, "cfg_lock", NULL, MTX_DEF)
#define CFG_LOCK_DESTROY(p) mtx_destroy(&(p)->lock)
#define CFG_LOCK(p) mtx_lock(&(p)->lock)
#define CFG_UNLOCK(p) mtx_unlock(&(p)->lock)
#define CALLOUT_LOCK_INIT(p) \
mtx_init(&(p)->periodic_lock, "periodic_lock", NULL, MTX_DEF)
#define CALLOUT_LOCK_DESTROY(p) mtx_destroy(&(p)->periodic_lock)
#define CALLOUT_LOCK(p) mtx_lock(&(p)->periodic_lock)
#define CALLOUT_UNLOCK(p) mtx_unlock(&(p)->periodic_lock)
struct nat64lsn_cfg *nat64lsn_init_instance(struct ip_fw_chain *ch,
in_addr_t prefix, int plen);
void nat64lsn_destroy_instance(struct nat64lsn_cfg *cfg);
void nat64lsn_start_instance(struct nat64lsn_cfg *cfg);
void nat64lsn_init_internal(void);
void nat64lsn_uninit_internal(void);
int ipfw_nat64lsn(struct ip_fw_chain *ch, struct ip_fw_args *args,
ipfw_insn *cmd, int *done);
#endif /* _IP_FW_NAT64LSN_H_ */