Changeset View
Changeset View
Standalone View
Standalone View
sys/netpfil/ipfw/nat64/nat64lsn.h
- This file was added.
/*- | |||||
* Copyright (c) 2015-2016 Yandex LLC | |||||
* Copyright (c) 2015-2016 Alexander V. Chernikov <melifaro@FreeBSD.org> | |||||
* All rights reserved. | |||||
* | |||||
* 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. | |||||
*/ | |||||
#ifndef _IP_FW_NAT64LSN_H_ | |||||
#define _IP_FW_NAT64LSN_H_ | |||||
#define NAT64_CHUNK_SIZE_BITS 6 /* 64 ports */ | |||||
#define NAT64_CHUNK_SIZE (1 << NAT64_CHUNK_SIZE_BITS) | |||||
#define NAT64_MIN_PORT 1024 | |||||
#define NAT64_MIN_CHUNK (NAT64_MIN_PORT >> NAT64_CHUNK_SIZE_BITS) | |||||
#define DEFAULT_MAX_PORTS (4 * NAT64_CHUNK_SIZE) | |||||
#define DEFAULT_NH_DEL_DELAY 120 | |||||
#define DEFAULT_PG_DEL_DELAY 300 | |||||
#define DEFAULT_ST_SYN_TTL 30 | |||||
#define DEFAULT_ST_CLOSE_TTL 30 | |||||
#define DEFAULT_ST_ESTAB_TTL (4 * 3600) | |||||
#define DEFAULT_ST_UDP_TTL 15 | |||||
#define DEFAULT_ST_ICMP_TTL 15 | |||||
#define DEFAULT_JMAXLEN 1024 /* Max outstanding requests in jq */ | |||||
struct st_ptr { | |||||
uint8_t idx; | |||||
uint8_t off; | |||||
}; | |||||
struct nat64lsn_portgroup; | |||||
/* | |||||
* Alloc 256 bytes per host (x64 cache, 16 portgroups) | |||||
*/ | |||||
struct nat64lsn_host { | |||||
struct in6_addr addr; | |||||
struct nat64lsn_host *next; | |||||
struct rwlock h_lock; /* Host states lock */ | |||||
struct st_ptr *phash; | |||||
uint16_t hsize; /* ports hash size */ | |||||
uint16_t pg_count; /* Number of portgroups used */ | |||||
uint16_t timestamp; /* Last altered */ | |||||
uint16_t spare; | |||||
/* 64 bytes on amd64 */ | |||||
struct nat64lsn_portgroup *pg_ptr[8];/* portgroup indices, 512 ports */ | |||||
//uintptr_t pg_idx[8];/* portgroup indices, 512 ports*/ | |||||
/* 128 bytes on amd64 */ | |||||
struct st_ptr st_hash[64]; | |||||
}; | |||||
#define NAT64_RLOCK_ASSERT(h) rw_assert(&(h)->h_lock, RA_RLOCKED) | |||||
#define NAT64_WLOCK_ASSERT(h) rw_assert(&(h)->h_lock, RA_WLOCKED) | |||||
#define NAT64_RLOCK(h) rw_rlock(&(h)->h_lock) | |||||
#define NAT64_RUNLOCK(h) rw_runlock(&(h)->h_lock) | |||||
#define NAT64_WLOCK(h) rw_wlock(&(h)->h_lock) | |||||
#define NAT64_WUNLOCK(h) rw_wunlock(&(h)->h_lock) | |||||
#define NAT64_LOCK(h) NAT64_WLOCK(h) | |||||
#define NAT64_UNLOCK(h) NAT64_WUNLOCK(h) | |||||
#define NAT64_LOCK_INIT(h) do { \ | |||||
rw_init(&(h)->h_lock, "NAT64 host lock"); \ | |||||
} while (0) | |||||
#define NAT64_LOCK_DESTROY(h) do { \ | |||||
rw_destroy(&(h)->h_lock); \ | |||||
} while (0) | |||||
/* Internal proto index */ | |||||
#define NAT_PROTO_TCP 1 | |||||
#define NAT_PROTO_UDP 2 | |||||
#define NAT_PROTO_ICMP 3 | |||||
#define NAT_MAX_PROTO 4 | |||||
extern uint8_t nat64lsn_rproto_map[NAT_MAX_PROTO]; | |||||
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)) | |||||
#ifdef __LP64__ | |||||
/* ffsl() is capable of checking 64-bit ints */ | |||||
#define _FFS64 | |||||
#endif | |||||
/* 16 bytes */ | |||||
struct nat64lsn_state { | |||||
union { | |||||
struct { | |||||
in_addr_t faddr; /* Remote IPv4 address */ | |||||
uint16_t fport; /* Remote IPv4 port */ | |||||
uint16_t lport; /* Local IPv6 port */ | |||||
}s; | |||||
uint64_t hkey; | |||||
} u; | |||||
uint8_t nat_proto; | |||||
uint8_t flags; | |||||
uint16_t timestamp; | |||||
struct st_ptr cur; /* Index of portgroup in nat64lsn_host */ | |||||
struct st_ptr next; /* Next entry index */ | |||||
}; | |||||
/* | |||||
* 1024+32 bytes per 64 states, used to store state | |||||
* AND for outside-in state lookup | |||||
*/ | |||||
struct nat64lsn_portgroup { | |||||
struct nat64lsn_host *host; /* IPv6 source host info */ | |||||
in_addr_t aaddr; /* Alias addr, network format */ | |||||
uint16_t aport; /* Base port */ | |||||
uint16_t timestamp; | |||||
uint8_t nat_proto; | |||||
uint8_t spare[7]; | |||||
#ifdef _FFS64 | |||||
uint64_t freemask; /* Mask of free entries */ | |||||
#else | |||||
uint32_t freemask[2]; /* Mask of free entries */ | |||||
#endif | |||||
struct nat64lsn_state states[NAT64_CHUNK_SIZE]; /* State storage */ | |||||
}; | |||||
#ifdef _FFS64 | |||||
#define PG_MARK_BUSY_IDX(_pg, _idx) (_pg)->freemask &= ~((u_long)1<<(_idx)) | |||||
#define PG_MARK_FREE_IDX(_pg, _idx) (_pg)->freemask |= ((u_long)1<<(_idx)) | |||||
#define PG_IS_FREE_IDX(_pg, _idx) ((_pg)->freemask & ((u_long)1<<(_idx))) | |||||
#define PG_IS_BUSY_IDX(_pg, _idx) (PG_IS_FREE_IDX(_pg, _idx) == 0) | |||||
#define PG_GET_FREE_IDX(_pg) (ffsl((_pg)->freemask)) | |||||
#define PG_IS_EMPTY(_pg) (((_pg)->freemask + 1) == 0) | |||||
#else | |||||
#define PG_MARK_BUSY_IDX(_pg, _idx) \ | |||||
(_pg)->freemask[(_idx) / 32] &= ~((u_long)1<<((_idx) % 32)) | |||||
#define PG_MARK_FREE_IDX(_pg, _idx) \ | |||||
(_pg)->freemask[(_idx) / 32] |= ((u_long)1<<((_idx) % 32)) | |||||
#define PG_IS_FREE_IDX(_pg, _idx) \ | |||||
((_pg)->freemask[(_idx) / 32] & ((u_long)1<<((_idx) % 32))) | |||||
#define PG_IS_BUSY_IDX(_pg, _idx) (PG_IS_FREE_IDX(_pg, _idx) == 0) | |||||
#define PG_GET_FREE_IDX(_pg) _pg_get_free_idx(_pg) | |||||
#define PG_IS_EMPTY(_pg) \ | |||||
((((_pg)->freemask[0] + 1) == 0 && ((_pg)->freemask[1] + 1) == 0)) | |||||
static inline int | |||||
_pg_get_free_idx(const struct nat64lsn_portgroup *pg) | |||||
{ | |||||
int i; | |||||
if ((i = ffsl(pg->freemask[0])) != 0) | |||||
return (i); | |||||
if ((i = ffsl(pg->freemask[1])) != 0) | |||||
return (i + 32); | |||||
return (0); | |||||
} | |||||
#endif | |||||
TAILQ_HEAD(nat64lsn_job_head, nat64lsn_job_item); | |||||
#define NAT64LSN_FLAGSMASK 0x0 | |||||
struct nat64lsn_cfg { | |||||
struct named_object no; | |||||
//struct nat64_exthost *ex; /* Pointer to external addr array */ | |||||
struct nat64lsn_portgroup **pg; /* XXX: array of pointers */ | |||||
struct nat64lsn_host **ih; /* Host hash */ | |||||
uint32_t prefix4; /* IPv4 prefix */ | |||||
uint32_t pmask4; /* IPv4 prefix mask */ | |||||
uint32_t ihsize; /* IPv6 host hash size */ | |||||
uint8_t plen4; | |||||
uint8_t plen6; | |||||
uint8_t nomatch_verdict;/* What to return to ipfw on no-match */ | |||||
uint8_t nomatch_final; /* Exit outer loop? */ | |||||
struct in6_addr prefix6; /* IPv6 prefix to embed IPv4 hosts */ | |||||
uint32_t ihcount; /* Number of items in host hash */ | |||||
int max_chunks; /* Max chunks per c/lient */ | |||||
int agg_prefix_len; /* Prefix length to count */ | |||||
int agg_prefix_max; /* Max hosts per agg prefix */ | |||||
uint32_t jmaxlen; /* Max jobqueue length */ | |||||
uint32_t flags; | |||||
uint16_t min_chunk; /* Min port group # to use */ | |||||
uint16_t max_chunk; /* Max port group # to use */ | |||||
uint16_t nh_delete_delay; /* Stale host 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 */ | |||||
uint32_t protochunks[NAT_MAX_PROTO];/* Number of chunks used */ | |||||
struct callout periodic; | |||||
struct callout jcallout; | |||||
struct ip_fw_chain *ch; | |||||
struct vnet *vp; | |||||
struct nat64lsn_job_head jhead; | |||||
int jlen; | |||||
char name[64]; /* Nat instance name */ | |||||
nat64_stats_block stats; | |||||
}; | |||||
struct nat64lsn_cfg *nat64lsn_init_instance(struct ip_fw_chain *ch, | |||||
size_t numaddr); | |||||
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); | |||||
void | |||||
nat64lsn_dump_state(const struct nat64lsn_cfg *cfg, | |||||
const struct nat64lsn_portgroup *pg, const struct nat64lsn_state *st, | |||||
const char *px, int off); | |||||
/* | |||||
* Portgroup layout | |||||
* addr x nat_proto x port_off | |||||
* | |||||
*/ | |||||
#define _ADDR_PG_PROTO_COUNT (65536 >> NAT64_CHUNK_SIZE_BITS) | |||||
#define _ADDR_PG_COUNT (_ADDR_PG_PROTO_COUNT * NAT_MAX_PROTO) | |||||
#define GET_ADDR_IDX(_cfg, _addr) ((_addr) - ((_cfg)->prefix4)) | |||||
#define __GET_PORTGROUP_IDX(_proto, _port) \ | |||||
(_proto - 1) * _ADDR_PG_PROTO_COUNT +\ | |||||
(_port >> NAT64_CHUNK_SIZE_BITS) | |||||
#define _GET_PORTGROUP_IDX(_cfg, _addr, _proto, _port) \ | |||||
GET_ADDR_IDX(_cfg, _addr) * _ADDR_PG_COUNT + \ | |||||
__GET_PORTGROUP_IDX(_proto, _port) | |||||
#define GET_PORTGROUP(_cfg, _addr, _proto, _port) \ | |||||
(_cfg)->pg[_GET_PORTGROUP_IDX(_cfg, _addr, _proto, _port)] | |||||
#define GET_PORTGROUP_BYSIDX(_cfg, _nh, _idx) \ | |||||
((struct nat64lsn_portgroup *)(_nh)->pg_ptr[(_idx) - 1]) | |||||
/* Chained hash table */ | |||||
#define CHT_FIND(_ph, _hsize, _PX, _x, _key) do { \ | |||||
unsigned int _buck = _PX##hash(_key) & (_hsize - 1); \ | |||||
_PX##lock(_ph, _buck); \ | |||||
_x = _PX##first(_ph, _buck); \ | |||||
for ( ; _x != NULL; _x = _PX##next(_x)) { \ | |||||
if (_PX##cmp(_key, _PX##val(_x))) \ | |||||
break; \ | |||||
} \ | |||||
if (_x == NULL) \ | |||||
_PX##unlock(_ph, _buck); \ | |||||
} while(0) | |||||
#define CHT_UNLOCK_BUCK(_ph, _PX, _buck) \ | |||||
_PX##unlock(_ph, _buck); | |||||
#define CHT_UNLOCK_KEY(_ph, _hsize, _PX, _key) do { \ | |||||
unsigned int _buck = _PX##hash(_key) & (_hsize - 1); \ | |||||
_PX##unlock(_ph, _buck); \ | |||||
} while(0) | |||||
#define CHT_INSERT_HEAD(_ph, _hsize, _PX, _i) do { \ | |||||
unsigned int _buck = _PX##hash(_PX##val(_i)) & (_hsize - 1); \ | |||||
_PX##lock(_ph, _buck); \ | |||||
_PX##next(_i) = _PX##first(_ph, _buck); \ | |||||
_PX##first(_ph, _buck) = _i; \ | |||||
_PX##unlock(_ph, _buck); \ | |||||
} while(0) | |||||
#define CHT_REMOVE(_ph, _hsize, _PX, _x, _tmp, _key) do { \ | |||||
unsigned int _buck = _PX##hash(_key) & (_hsize - 1); \ | |||||
_PX##lock(_ph, _buck); \ | |||||
_x = _PX##first(_ph, _buck); \ | |||||
_tmp = NULL; \ | |||||
for ( ; _x != NULL; _tmp = _x, _x = _PX##next(_x)) { \ | |||||
if (_PX##cmp(_key, _PX##val(_x))) \ | |||||
break; \ | |||||
} \ | |||||
if (_x != NULL) { \ | |||||
if (_tmp == NULL) \ | |||||
_PX##first(_ph, _buck) = _PX##next(_x); \ | |||||
else \ | |||||
_PX##next(_tmp) = _PX##next(_x); \ | |||||
} \ | |||||
_PX##unlock(_ph, _buck); \ | |||||
} while(0) | |||||
#define CHT_FOREACH_SAFE(_ph, _hsize, _PX, _x, _tmp, _cb, _arg) do { \ | |||||
for (unsigned int _i = 0; _i < _hsize; _i++) { \ | |||||
_PX##lock(_ph, _i); \ | |||||
_x = _PX##first(_ph, _i); \ | |||||
_tmp = NULL; \ | |||||
for (; _x != NULL; _tmp = _x, _x = _PX##next(_x)) { \ | |||||
if (_cb(_x, _arg) == 0) \ | |||||
continue; \ | |||||
if (_tmp == NULL) \ | |||||
_PX##first(_ph, _i) = _PX##next(_x); \ | |||||
else \ | |||||
_tmp = _PX##next(_x); \ | |||||
} \ | |||||
_PX##unlock(_ph, _i); \ | |||||
} \ | |||||
} while(0) | |||||
#define CHT_RESIZE(_ph, _hsize, _nph, _nhsize, _PX, _x, _y) do { \ | |||||
unsigned int _buck; \ | |||||
for (unsigned int _i = 0; _i < _hsize; _i++) { \ | |||||
_x = _PX##first(_ph, _i); \ | |||||
_y = _x; \ | |||||
while (_y != NULL) { \ | |||||
_buck = _PX##hash(_PX##val(_x)) & (_nhsize - 1);\ | |||||
_y = _PX##next(_x); \ | |||||
_PX##next(_x) = _PX##first(_nph, _buck); \ | |||||
_PX##first(_nph, _buck) = _x; \ | |||||
} \ | |||||
} \ | |||||
} while(0) | |||||
#endif /* _IP_FW_NAT64LSN_H_ */ | |||||